notifyDataSetChanged()无法处理自定义的RecyclerView适配器

时间:2017-11-01 19:47:22

标签: android android-recyclerview recycler-adapter notifydatasetchanged

我正在尝试创建一个显示当前状态栏通知列表的recyclerView。我创建了一个自定义适配器(NotiRecyclerAdapter),其List NotificationItemInformation

public class NotificationItemInformation
{
  int iconId,noitId;
  String packageName;
  Drawable notiIcon;
}

我使用SQLite DB来存储所有通知。 无论何时发布或删除通知,NotificationListenerService都会从数据库中写入和删除。

我使用名为

的方法
public List<NotificationItemInformation> ReadNotilist (Context context);

(在myDBHelper中)将DB的内容读取到名为List NotificationItemInformation data的{​​{1}}(在我的主要活动中是全局的,公共的和静态的)。 然后我使用adapter(在我的主要活动中也是全局的,公共的和静态的)来取data并将其设置为我RecyclerView方法中的onCreate MainActivity

到目前为止一切运作良好。我可以看到填充了当前RecyclerView通知的StatusBar

问题是列表不会更新(如果有新通知),直到我重新启动活动。我试着打电话......

MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this); // dbh is DBhelper object
MainActivity.adapter.notifyDataSetChanged();

...我的onNotificationPostedNotificationListenerService(在添加到数据库之后)。但是在我重新开始活动之前,RecyclerView仍然没有得到更新。

如果你想看一下,这是我的MainActivity

public class MainActivity extends AppCompatActivity
{

    SQLiteDatabase db;
    DBHelper dbh;

    RecyclerView notificationIconRecyclerView;
    public static NotiRecyclerAdapter adapter;
    public static List<NotificationItemInformation> data = Collections.EMPTY_LIST;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dbh = new DBHelper(this);
        db = dbh.getDb();
        notificationIconRecyclerView = (RecyclerView) findViewById(R.id.notificationIconRecyclerView);
        data = dbh.ReadNotilist(this);
        adapter = new NotiRecyclerAdapter(this,data);
        notificationIconRecyclerView.setAdapter(adapter);
        notificationIconRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,true));
    }
}

以下是RecyclerView

的自定义适配器
public class NotiRecyclerAdapter extends RecyclerView.Adapter<NotiRecyclerAdapter.MyViewHolder>
{

    private LayoutInflater inflater;
    List<NotificationItemInformation> data = Collections.emptyList();

    NotiRecyclerAdapter(Context context, List<NotificationItemInformation> data)
    {
        inflater = LayoutInflater.from(context);
        this.data = data;
    }


    @Override
    public void registerAdapterDataObserver(RecyclerView.AdapterDataObserver observer)
    {
        super.registerAdapterDataObserver(observer);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        View view = inflater.inflate(R.layout.custom_recyclerview_item,parent,false);
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position)
    {
        NotificationItemInformation current = data.get(position);
        holder.recyclerItemIcon.setImageDrawable(current.notiIcon);
    }

    @Override
    public int getItemCount()
    {
        return data.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder
    {
        ImageView recyclerItemIcon;
        public MyViewHolder(View itemView)
        {
            super(itemView);
            recyclerItemIcon = itemView.findViewById(R.id.notiRecyclerItemIcon);
        }
    }

}

2 个答案:

答案 0 :(得分:0)

不要重置对数据对象的引用。而是尝试这样的事情:

MainActivity.data.clear();
MainActivity.data.addAll(dbh.ReadNotilist(this));
MainActivity.adapter.notifyDataSetChanged();

答案 1 :(得分:0)

在适配器的构造函数中,编写

this.data = data;

这会将传递给构造函数的List<NotificationItemInformation>分配给适配器的data字段。您的适配器构造如下:

adapter = new NotiRecyclerAdapter(this,data);

这意味着您的MainActivity.data字段和adapter.data字段都指的是相同的列表。

后来你写道:

MainActivity.data.clear();
MainActivity.data = dbh.ReadNotilist(this);
MainActivity.adapter.notifyDataSetChanged();

第一行清除MainActivity.data adapter.data(请记住,由于构建适配器的方式,它们是相同的列表)。第二行为MainActivity.data分配了一个新列表,但不会以任何方式影响adapter.data。第三行通知适配器数据集已更改(它已更改;已清除),但您的适配器不会&#34;&#34;&#34;来自dbh.ReadNotilist()的新信息。

AChez9的答案有效,因为使用addAll()代替分配(=)意味着MainActivity.dataadapter.data仍指向同一List },所以适配器将&#34;看&#34;新信息。

这就是为什么当您从外部来源接受列表时,创建列表的副本通常是正确的。换句话说,适配器的构造函数可能希望这样做:

this.data = new ArrayList<>(data);

这意味着它是安全的&#34;从更改传递给它的列表(在这种情况下,MainActivity.data)。但这意味着您还需要为您的活动提供一种正确更新适配器的方法。我建议使用这样的方法:

public void updateData(List< NotificationItemInformation> data) {
    this.data = new ArrayList<>(data);
    notifyDataSetChanged();
}