关于ListView中adapter调用notifyDataSetChanged失效的原因总结
一、前言
相信很多人都曾经被这个问题困扰,当然我也是这样过来的,原来以为只要数据变了,调用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;
- }
- }
- public void setData(List<People> newPeopleList){
- this.peopleList = newPeopleList;
- }
四、总结
上面说的这么多,不知道大家有没有懂,其实根本原因就是listview+adapter+数据源这三者的绑定,如果因为指向新的引用造成三者没有了原来的捆绑关系,自然调用notifyDataSetChanged()就会失效。
源码下载
数据并没有刷新!
查看log,调用notifyDataSetChanged()后,onCreateViewHolder、onBindViewHolder方法并没有执行。
找了很久,最后在StackOverFlow上找到了答案,原文在这里
原来在我后台接收到数据调用更新界面回调方法时,其实和当前Activity不在同一个线程,我忙傻了把这点给忘了。
在回调里应该通过Handler发送数据到主线程,然后再给adapter里填数据,调用notifyDataSetChanged();
线程回调方法里:
Message handleMsg = new Message();
Bundle bundle = new Bundle();
bundle.putParcelable("1",message);
handleMsg.setData(bundle);
handleMsg.what = 1;
updateChatHandler.sendMessage(handleMsg);
处理消息的Handler:
Handler updateChatHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
EMMessage message = msg.getData().getParcelable("1");
// UIUtils.showToastSafe(WaitForChatActivity.this, "接收到消息的回调" + message.getBody());
setChatDataFromNet(message);
if (adapter != null) {
addData2Adapter(receiveMsg, false);
}
break;
}
super.handleMessage(msg);
}
};
总结
更新数据时在主线程填数据,然后再调用RecyclerView.Adapter的 notifyDataSetChanged方法。
Android 开发过程中经常遇到更新界面没反应的情况,一开始我总是觉得自己代码这么完美!一定是数据或者编译器问题,结果一次次被打脸。T。T
今天总结下开发过程中遇到的几种更新 UI 没反应原因:
- 数据为空
有时候服务端返回数据有误或者自己传递的数据为空,可以打个 Log 或者 跟个断点看看。
- 在子线程更新 UI
有时候在 请求接口回调、ListView 或者 RecyclerView 的 Adapter 里需要进行一些 UI 更新,这时不起作用的原因大多是因为我们在 子线程中更新UI。
子线程更新 UI 的方法有好多种,最终目的都是把消息发到主线程去操作:
写个 Handler 里进行 UI 操作,子线程 发送消息
在runOnUiThread中
Activity.runOnUiThread(new Runnable() {
@Override
public void run() {
//do the ui-job
}
});
或者 post 到主线程
myView.post(new Runnable() {
@Override
public void run() {
//do the ui-job
}
})
3.方法调用错误
最常见的就是修改 ImageVIew 图片,应该调用
setImageResource
或者其他 setImageXXX 方法
而不是
setBackground
等 setBackgroundXXX 方法,后者只是修改背景,而不是图片本身。