关于ListView中adapter调用notifyDataSetChanged失效的原因总结

本文深入解析了Android中ListView使用Adapter更新数据的原理及常见问题,包括数据源更新、引用变化和适配器通知机制等方面,并提供了有效解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于ListView中adapter调用notifyDataSetChanged失效的原因总结

一、前言


       相信很多人都曾经被这个问题困扰,当然我也是这样过来的,原来以为只要数据变了,调用adapter的notifyDataSetChanged就会更新列表,然而结果却没有实现,其实是在一些细节上没有注意造成的,所以现在对这个问题进行下总结希望可以帮助到有需要的人。


二、原因分析


有以下三个原因:

1、数据源没有更新,调用notifyDataSetChanged无效。

2、数据源更新了,但是它指向新的引用,调用notifyDataSetChanged无效。

3、数据源更新了,但是adpter没有收到消息通知,无法动态更新列表。

一般来说,我们都是第二个原因造成的。


三、举例分析


分析了原因还是直接写个例子来说明,这样更加清楚。
正常情况:点击添加,然后点击更新界面。


事件代码:
[java]  view plain  copy
  1. public void onClicked(View view) {  
  2.        switch (view.getId()) {  
  3.            case R.id.btn_add://添加  
  4.                for (int i = 0; i < 2; i++) {  
  5.                    People people = new People("女神" + i, imgs[2]);  
  6.                    peopleList.add(people);  
  7.                }  
  8.   
  9.                break;  
  10.            case R.id.btn_add2://添加失败  
  11.                peopleList = new ArrayList<>();  
  12.                for (int i = 0; i < 2; i++) {  
  13.                    People people = new People("女神" + i, imgs[3]);  
  14.                    peopleList.add(people);  
  15.                }  
  16.                // myAdapter = new MyAdapter(this, peopleList);  
  17.   
  18.                break;  
  19.            case R.id.btn_replace://通知更新  
  20.                peopleList = new ArrayList<>();  
  21.                for (int i = 0; i < 2; i++) {  
  22.                    People people = new People("女神" + i, imgs[4]);  
  23.                    peopleList.add(people);  
  24.                }  
  25.                myAdapter.setData(peopleList);  
  26.                break;  
  27.            case R.id.btn_notify://更新  
  28.                myAdapter.notifyDataSetChanged();  
  29.                break;  
  30.            default:  
  31.   
  32.                break;  
  33.        }  
  34.    }  

myAdapter = new MyAdapter(this, peopleList)
实例化MyAdapter,这里两个参数。点击添加后数据源peopleList添加了两个People对象,点击更新,实际就是调用notifyDataSetChanged(),listview正常更新,ok没有问题!

接着演示个失败的案例。

      我已经拼命点了怎么就是没有效果,对比上面的代码,发现点击失败的case里多了一句话,
      peopleList = new ArrayList<>();
       难道就是这句造成的?没错,就是它,也就是上面的原因2。虽然数据源更新了,但是它指向新的引用,可是我们的Adapter绑定的还是原来数据源的引用,自然你调用更新,我们的Adapter认为是没有变化,所以失效。没事我们重新绑定下Adapter的数据源,打开上面注释的话,再来,可是结果你会发现这样也是不行的,因为虽然Adaper是更新了数据源,可是这个Adapter和原来的Adapter已经不一样了,listView却还是不知道这样的变化,所以调用也会无效。
正确的做法是现在Adaper写一个更新数据源的方法,这样就不会出现问题了。(上面点击通知更新的情况)
[java]  view plain  copy
  1. public void setData(List<People> newPeopleList){  
  2.        this.peopleList = newPeopleList;  
  3.    }  


四、总结


       上面说的这么多,不知道大家有没有懂,其实根本原因就是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 没反应原因:

  1. 数据为空

有时候服务端返回数据有误或者自己传递的数据为空,可以打个 Log 或者 跟个断点看看。

  1. 在子线程更新 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 方法,后者只是修改背景,而不是图片本身。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值