一、前言
相信很多人都曾经被这个问题困扰,当然我也是这样过来的,原来以为只要数据变了,调用adapter的notifyDataSetChanged就会更新列表,然而结果却没有实现,其实是在一些细节上没有注意造成的,所以现在对这个问题进行下总结希望可以帮助到有需要的人。
二、原因分析
1、数据源没有更新,调用notifyDataSetChanged无效。
2、数据源更新了,但是它指向新的引用,调用notifyDataSetChanged无效。
3、数据源更新了,但是adpter没有收到消息通知,无法动态更新列表。
一般来说,我们都是第二个原因造成的。
三、举例分析
分析了原因还是直接写个例子来说明,这样更加清楚。
正常情况:点击添加,然后点击更新界面。
事件代码:
public void onClicked(View view) {
switch (view.getId()) {
case R.id.btn_add://添加
for (int i = 0; i < 2; i++) {
People people = new People("女神" + i, imgs[2]);
peopleList.add(people);
}
break;
case R.id.btn_add2://添加失败
peopleList = new ArrayList<>();
for (int i = 0; i < 2; i++) {
People people = new People("女神" + i, imgs[3]);
peopleList.add(people);
}
// myAdapter = new MyAdapter(this, peopleList);
break;
case R.id.btn_replace://通知更新
peopleList = new ArrayList<>();
for (int i = 0; i < 2; i++) {
People people = new People("女神" + i, imgs[4]);
peopleList.add(people);
}
myAdapter.setData(peopleList);
break;
case R.id.btn_notify://更新
myAdapter.notifyDataSetChanged();
break;
default:
break;
}
}
myAdapter = new MyAdapter(this, peopleList)
实例化MyAdapter,这里两个参数。点击添加后数据源peopleList添加了两个People对象,点击更新,实际就是调用notifyDataSetChanged(),listview正常更新,ok没有问题!
接着演示个失败的案例。
我已经拼命点了怎么就是没有效果,对比上面的代码,发现点击失败的case里多了一句话,
peopleList = new ArrayList<>();
难道就是这句造成的?没错,就是它,也就是上面的原因2。虽然数据源更新了,但是它指向新的引用,可是我们的Adapter绑定的还是原来数据源的引用,自然你调用更新,我们的Adapter认为是没有变化,所以失效。没事我们重新绑定下Adapter的数据源,打开上面注释的话,再来,可是结果你会发现这样也是不行的,因为虽然Adaper是更新了数据源,可是这个Adapter和原来的Adapter已经不一样了,listView却还是不知道这样的变化,所以调用也会无效。
正确的做法是现在Adaper写一个更新数据源的方法,这样就不会出现问题了。(上面点击通知更新的情况)
public void setData(List<People> newPeopleList){
this.peopleList = newPeopleList;
}
四、总结
上面说的这么多,不知道大家有没有懂,其实根本原因就是listview+adapter+数据源这三者的绑定,如果因为指向新的引用造成三者没有了原来的捆绑关系,自然调用notifyDataSetChanged()就会失效。
源码下载