单例持有activity的引用导致list的adpter.notifyDataSetChanged()调用无效,界面不刷新的问题分析。

一、问题背景

帮助朋友做一个项目中的蓝牙模块,需求是进入功能界面,开启蓝牙连接,离开界面后断开蓝牙连接,已被给后续的模块使用蓝牙资源。

常规逻辑:判断蓝牙权限->扫描蓝牙设备->配对连接->数据传输->关闭蓝牙连接. 每次进入、离开均会连接和断开连接蓝牙。

问题现象:对于同一个蓝牙界面,第一次进入能够显示搜索到的蓝牙设备。当退出后,再次进入不能够显示蓝牙设备,也就无法后续的操作。

二、问题分析

好了,至此,问题的现象和项目中的步骤已经明确。废话不多说先来几段硬核的代码,看看我们的实现主流程。

初始化:涉及到一个搜索的dialog,里面显示搜索到的devices,还有控制蓝牙连接&数据解析的类。

 

 扫描设备:

蓝牙设备的监听通过广播完成(有兴趣的小伙伴可以自行了解蓝牙相关知识,这里只做简单介绍)

资源释放工作:

 

当前我是把蓝牙操作界面所涉及都放在这个基类:BluetoothActivityCompat中。

当我拿到问题时候,简单看了下流程,然后关键点加了一些日志,分别是initview, onStartScan,  onFoundDevice(),了解是否检测到了蓝牙设备,已经管理蓝牙设备的list里面的数据情况。

通过日志分析,生命周期方法正常执行,并且管理蓝牙的集合数据正常,设备可以扫描到蓝牙设备,只是第一次在mSearchingDialog中显示了已经扫描到的蓝牙设备,后续扫描到的设备不显示,至此问题定性完成:UI显示没有及时更新导致,蓝牙功能正常。

发现了问题的根因,接下来修改:首先

我们可以看到原先的思路是,调用mBluetoothAdapter.notifyDataSetChanged()对数据进行操作,因为涉及到多出的数据清除,添加。所以我修改了数据刷新的方式,并将adpter初始化中的数据源修改

 adapter中添加setData()方法当运行后惊喜的发现,依然不行。之后是网上百度环节,百度给出的场景多为:adapter中的数据源被修改了地址的指针,姑且称作数据源为mData, 一般为mData = list;修改了mData的内存地址,然而adapter中的数据依然指向原有的数据集地址,好似黑夜中看到了一丝丝的火光,恨不得立马燃爆我的内心。马上开箱去检查我的代码。

然后做出修改:

这样子好像大功告成,刷新了数据并且避免了数据源指向新的对象, 堪称完美。但是打脸的时刻在下一秒来临,一顿 running,依旧如故。至此我陷入了无穷的思考,然后把思绪迁移到对象的释放上来,会不会是由于dialog没有销毁,或者是adapter没有销毁导致的呢?然后在destroy中添加了释放的代码,并且在initview中添加了对象的日志打印;

 

经过日志分析后发现并无异样,正常的释放和初始化,并且开始adapter=null,这一切看似都没有问题。那么我怀疑是不是这个activity的启动模式是singletask/singletop呢,导致了重新进去并没有销毁把之前的界面展示出来。赶紧查看mainifest.xml啥也没发现,一看是默认的standard。在我后续的测试中发现了,多测试几次出现了crash,原因是mBlueetoothAdapter不能为null,一看代码,映射到onStartScan() 中

 按照常规分析,此activity是standard模式,生命周期中执行了onDestroy(),应该每次进入都会产生一个新的实例,对应java的内存栈的话,应该是隔离的,这里的crash是在initview()执行后,按照道理不会产生crash,日志为证:

 如果说crash 的话只有一个原因,activity的实例依然存在java内存中, 我并没有进行内存分析,先按照我的思路寻找内存泄露的点。一顿查阅代码后发现,此activity中引用了一个单例的蓝牙管理类

 确实通过listener的方式持有了activity的引用,导致释放不掉,再次进入也就会产生操作的还是上一个activity 的对象的问题,就会出现进入展示了一个新的dialog,但是没有展示数据,因为那些对象全都是上一个的。

修改方案:每一个都是standard模式,没有必要单例,所以改成非单例模式。也可以通过WeakReference来完成优化。此处我选择第一种。至此问题解决,再次运行完美通过。

三、总结

1.遇到问题需要先找到根因,再指定解决方案,不能急躁,不然越着急越是搞不定。

2.adapter 刷新数据失效的原因,数据源变为新的对象,指向新的地址。 至于有助于理解java内存中的对象的引用机制。

3.内存泄露的现象,分析机制,已经如何解决。即使之前我可能看过很多博客,但是没有亲自遇到修改相关问题,理解更加深入了一步。

好了,今天周五,祝愿各位看官每天都能像周五一样迎接周末。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>