一、背景介绍
最近2个多月,我一直在开发安卓应用。由于我只是个新手,对Java和Android Studio都了解不深,基本是边学习,边开发。我手头最主要的参考资料就是欧阳燊先生编著的《Android App开发入门与项目实战》,前段时间才看到第12章,了解到了RecyclerView循环视图的妙用,立即就照本宣科的用到了自己开发的一款商品扫描盘点的app中,11月份,该app已经交给公司营销部门的同事进行实测,同事反馈挺好的,帮他们解决了工作中的麻烦。软件的开发并不那么顺利,我遇到了不少的问题,还好都解决了(相关内容见下面的链接)。
SQLite 查询语句遇到的坑——条件语句等号后的参数没用单引号括起来的异常
https://blog.csdn.net/bahamutj/article/details/134044809
Android 应用开发学习-自定义月份选择器
https://blog.csdn.net/bahamutj/article/details/134211869
Android 应用开发-解决使用华为统一扫描服务的app在鸿蒙系统的手机上不能扫码的问题
https://blog.csdn.net/bahamutj/article/details/134341225
由于当时我是照着书上的源代码进行的开发,因为应用场景的不同,导致了编写出的代码存在一些不尽如人意的地方,我个人感觉可以优化,但那款app开发已经完成,我暂时也就不想去修改了。之后又接到另外一个部门同事的需求开发一款危险废物管理方面的app,以帮助同事快速生成二维码和相应的数据记录。这款app也会用到RecyclerView循环视图,我本以为有了之前的经验,这次的开发会很顺利,结果还是遇到了坑。
二、问题描述
前面提到了第一次用到RecyclerView循环视图我是照着《Android App开发入门与项目实战》中的内容填写的代码,存在一些可优化的地方。这次开发,与RecyclerView循环视图相关的代码,有一部分我是重新编写的,没有直接复制之前的代码。结果出了问题。
代码完成后,我照例进行调试,创建了几条测试用的数据记录后,测试在RecyclerView循环视图中的显示情况。RecyclerView循环视图初始化时很正常,从数据库中读取到了数据,并显示在了RecyclerView循环视图中(如下左图,查询到的数据都是2023年的)。我将年度从2023年改成2022年后,软件会再次进行查询。我在创建测试用的数据的时候,特意创建了一条2022年的数据,正常情况下,选择了2022年后,会将数据更新到RecyclerView循环视图中,但这次没有(如下右图)。
我又来回了进行调试,结果都一样,进入这个页面时,可以正常显示数据,但更改参数就是不会显示数据,如不切换到其他年度,再换会2023年,也不显示数据。这就很奇怪了。
我之后又在程序中添加了一些Log语句输出相关的信息,通过Android Studio的Logcat检查程序运行过程中Log的输出结果。其中查询数据库后,通过Log语句打印查询结果的个数,发现查询是成功的。并且运行过程中软件没有闪退,也没有警告提示,这可把我整懵了。
三、解决办法
无奈之下,只好求助于万能的度娘,通过一番搜索,结果在CSDN里找到了一篇相关的博文(链接如下):
【错误记录】Android中,notifyDataSetChanged()不能正确更新listView问题
虽然这篇文章是关于ListView的问题,但RecyclerView循环视图是ListView的增强版,用法上也有很多相似之处。仔细看过这篇博文之后,我就大致明白了我所遇到的问题是怎么事了。
这篇博文中的 解决方法② 是这样描述的:
对于Arraylist类型的数据data,只在原对象上修改,不能重新赋值,因为重新赋值实质上改变了data所指向的对象,导致adapter的绑定出现问题,这可能也是notifyDataSetChanged()一个使用条件。
我遇到的问题就是这样的,我软件中的Arraylist类型的变量是mRecordsList,在对年度发生改变后,监听器就会执行如下的语句代码。先是清空mRecordsList,然后进行数据查询,并将结果通过赋值语句传递给mRecordsList,最后通知RecyclerView循环视图的适配器mAdapter,数据发生了变化,由适配器更新RecyclerView循环视图。
问题就出在“mRecordsList = mHelper.query(condition); ” 语句上。
而这些代码正是这次重新编写的代码,之前的app中对mRecordsList的数据更新是用的Add方法,逐条添加的,因此没有出现这个问题。
// 在从数据库查询数据之前,先将当前mRecordsList清空
// mRecordsList是Arraylist类型,该变量存放的数据会显示在RecyclerView循环视图中
if (mRecordsList.size() > 0) {
mRecordsList.clear();
mAdapter.notifyDataSetChanged(); // 通知适配器整列数据发生了变化
}
// 通过数据库帮助器查询符合条件 condition 的数据,并返回给mRecordsList
// 问题就出现在这条赋值语句!!!!!!!
mRecordsList = mHelper.query(condition);
// 通知适配器语句,下面两条任选一条
//mAdapter.notifyDataSetChanged(); // 通知适配器整列数据发生了变化
mAdapter.notifyItemInserted(0); // 通知适配器在指定位置插入了新项
找到了症结所在,稍加修改就可以了,修改后的代码如下:
if (mRecordsList.size() > 0) {
mRecordsList.clear();
mAdapter.notifyDataSetChanged(); // 通知适配器整列数据发生了变化
}
List<WasteInfo> tempList = mHelper.query(condition);
mRecordsList.addAll(tempList);
//mAdapter.notifyDataSetChanged(); // 通知适配器整列数据发生了变化
mAdapter.notifyItemInserted(0); // 通知适配器在指定位置插入了新项
由于逐条添加比较麻烦,我在网上搜索了一下,发现可以用addAll方法将一个Arraylist类型中的元素添加到另外一个Arraylist类型的变量中,这样语句就简洁很多了。
重新运行软件,问题解决。
这次不但解决了一个开发中遇到的问题,还学到了一些新的知识,让我对Java的理解有更深入了一点点。