利用回调函数解决分类式Listview的notifyDataSetChanged在adapter中不执行的问题

本文分享了作者在实现一个程序锁App过程中遇到的问题及解决方案,重点介绍了如何使用嵌套Adapter来实现分类ListView,并解决了convertView为空、不同类型的item回收利用以及notifyDataSetChanged执行但getView不执行等问题。

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

 

本文从头开始回顾我的项目,想要直接看题目解决方法的请跳到第三个问题。

最近打算做一个程序锁app练练手,在GitHub上找到了基础代码进行修改。

原代码https://github.com/caiwenshuo/asLockApp实现的listview是将锁定的app和未锁定的app混杂在一起显示,我希望实现的是锁定与未锁定的app分开显示,并且在listview有分类标签。

原效果图

 

改后效果图

于是我参考了https://blog.youkuaiyun.com/wellke666/article/details/50561770

他的原理是通过两个adapter嵌套,外层的adapter用于分类,判断要显示的item是属于分类标签还是内容,再分别交给不同的adapter去处理。

第一个问题:convertview == null

在应用这个分类listview后遇到的第一个问题就是在初始化界面时convertview == null 判断除了第一行外其他都不成立的。因为若convertview == null成立则为部件建立对象。这就导致其后生成的item因为没有初始化而报错。

后来发现原因出在了xml文件内,更改layout_height等属性后就可以做出正确判断了。

关于这个问题可参考: https://mp.youkuaiyun.com/postedit/82263578

第二个问题:不同类型item回收利用

我重写的ListViewAdapter在生成满屏的item后,滚动屏幕,新的item会利用旧的item的布局,免去了生成新布局的消耗。这在没有使用分类listview 之前是能很好运作的。但在使用后,由于回收的item有的是title类型,有的是content类型,他们的布局并不相同,没办法回收利用。这个问题我目前是粗暴地放弃回收利用,每次都产生新item。网上有说利用itemtype函数判断的。

第三个问题:notifyDataSetChanged执行而getview不执行

采用嵌套式adapter遇到的问题就是现在不能实时刷新页面了,比如我点击锁定,锁定按钮不会变成已锁定,也不会重新分类,但只要我滚动屏幕,再滚回去,就能看到变化。这说明我的数据源是有变化的。那肯定是就是我最内层的notifydatasetchanged函数没有执行力。(说明我的问题不是网上常说的list指针问题)

于是我重写了notifydatasetchanged输出日志,

 @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        System.out.println("log: notifydatasetchanged is executed"+getCount());
    }

结果发现notifydatasetchanged在我每次点击锁定时都有执行,getcount也有变化。

那为什么视图没有变化呢?据我理解,notifydatasetchanged函数实际上判断数据有无变化,有则重新渲染,那么肯定得重新执行getview()了,于是我在getview中加入log。运行证明,在我点击锁定button后getview()并没有运行。难怪视图没有刷新。

经过查了stackover、csdn各种文章后,虽然并没有人能准确地解决我的问题,但还是给了我些启发。

我觉得我的问题是adapter嵌套引起的。我在activity中的Listview绑定的是最外层的adapter,而调用notifydatasetchanged则是由第二层adapter调用,这个adapter并没有与listview绑定,所以他即使调用了notifydatasetchanged可能也无法改变listview。

我尝试解决这个问题。我想到的方法是用回调函数,在按钮被点击时让第二层的adapter调用第一层的notifydatasetchanged,这样就可以完美解决adapter和listview的对应问题。

 public interface Callback{
        public abstract void callback();
    }
cb=new Callback() {
            @Override
            public void callback() {
                notifyDataSetChanged();
            }
        };

重写回调函数


                if (listItems.get(position).get("flag").equals("已锁定")) {
                    listItems.get(position).put("flag", "锁定");
                    otherlistItems.add(listItems.get(position));
                    listItems.remove(position);

                    if(dataBaseUtil.delete(app) == 0){
                        Log.i(tableName, "delete failed! ");
                    }
                    else {
                        Log.i(tableName, "delete success! ");
                    }
                    System.out.println("delete");
                }
                else {
                    listItems.get(position).put("flag", "已锁定");
                    otherlistItems.add(listItems.get(position));
                    listItems.remove(position);
                    if(dataBaseUtil.insert(app) == -1){
                        Log.i(tableName, "insert failed! ");
                    }
                    else {
                        Log.i(tableName, "insert success! ");
                    }
                    System.out.println("lock");
                }
                //thread.start();

                    cbc.callback();

对回调函数不了解可参考: https://blog.youkuaiyun.com/Maoxf_Boss/article/details/51040072 

在第二层adapter调用callback()

重新运行可以看到现在的界面就可以根据我们的点击实时刷新了~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值