项目中多次操作SharedPreferences导致ANR场景的解决

简介: 随着时代的进步,移动端广告的投放变得越来越多样化,为了接近市场,不少公司自己研发了SDK去收集用户的一些信息以及行为用于分析,根据分析结果使用自定义广告(自定义View)的方式继续向用户进行展示,以提高展示率和点击率。目前关于广告商方面的选择,国内的广告变现普遍较低,首选应该是接入谷歌广告。随着业务的发展,在一段时间后,公司开始转变成广告接收方,并靠自己的SDK来进行广告的投放,以及优化。

项目背景:

 随着时代的进步,移动端广告的投放变得越来越多样化,为了接近市场,不少公司自己研发了SDK去收集用户的一些信息以及行为用于分析,根据分析结果使用自定义广告(自定义View)的方式继续向用户进行展示,以提高展示率和点击率。

目前关于广告商方面的选择,国内的广告变现普遍较低,首选应该是接入谷歌广告。随着业务的发展,在一段时间后,公司开始转变成广告接收方,并靠自己的SDK来进行广告的投放,以及优化。

以定位来获取广告的方式为例:

1.首先利用用户的定位等权限来获取经纬度

1.jpg2.将经纬度上传至国内某定位SDK,获取具体信息

2.jpg

3.最后根据定位信息来获取广告并预加载为广告展示做准备

3.jpg

所遇到的挑战:

  在项目功能完成后准备上架前,会对项目进行一系列的测试,但是ANR问题在测试过程中很难完成复现,在使用多个机型测试的过程中几乎没有ANR问题的记录。但是在用户的实际使用过程中,由于Android碎片化的严重,加上用户的一些操作的习惯等,会导致出现ANR的问题。面对一些大型的厂家,ANR出现时会弹窗引导用户关闭软件,会导致使用体验不好,造成用户的流失。

解决问题的步骤:

  在项目一个多月的异常收集中,出现过几次ANR的问题。

l  分析异常收集中ANR日志将问题锁定在SharedPreferences上,排查过程比较麻烦,在锁定了问题后,开始对问题进行分析。

l  查看Android文档:在项目中,团队使用SharedPreferences读写配置文件,均采用了官方的推荐做法,调用apply来提交,调用这个方法时,先写入内存中,再将任务加入队列中,会在异步线程中做落盘的操作,这个操作理论上来说是没有问题的,也是google官方推荐的做法。

l  阅读源码:

4.jpg

在此过程中发现谷歌官方注释:

If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself.

翻译:如果SharedPreferences上的另一个编辑器执行常规的commit(),而apply()仍然未完成,则commit()将阻塞,直到所有异步提交以及提交本身都完成。

 

l  锁定问题:主线程调用了 `QueuedWork.waitToFinish()`,没有待执行的任务,直接执行 finisher,进行阻塞等待, 直到写入文件成功后恢复执行, 这时候如果等待时间过长,在一些市面上性能差的中低端机型上就会很容易出现ANR8.0以下)

问题的解决

当时的优化:

1. 减小sp对应的文件的大小,按照分类去读写对应的sp文件。

2. sp的读写轻量的、小的配置信息,将类似JSON的数据交给其他方式保存。

3. 当需要多次调用Put系列方法,当逻辑确认不需要立即读取时,在最后一次调用commitapply即可。

 

最近朋友推了一篇字节的博客(以下文字以及图片来源于字节今日头条团队)

l  思路:如果能让sPendingWorkFinishers.poll()返回为null,则这里的等待行为直接就跳过去了,sPendingWorkFinishers是个ConcurrentLinkedQueue集合,可以直接动态代理这个集合,覆写poll方法,让其永远返回null,这个时候UI永远不会等待子线程写入文件完毕,事实证明这种方式简单有效。

5.jpg

l  针对这种写入等待的ANR问题,还有一种就是全局替换写入方式,通过插桩的方式,替换所有的API实现,采用其他的存储方式,这种方式修复成本和风险较大,但是后期可以随机的替换存储方式,使用比较灵活。


友盟平台相关SDK初体验:

由于ANR的比较难复现,于是写一个方法,反复对SharedPreferences进行操作,以达到类似情况的复现。

6.jpg

出现问题,通过友盟U-APM平台定位

7.jpg

找到问题后,进行文中思路的操作即可。

 

总结

在情景中,由于Android太过碎片化,又不得直接舍弃低版本用户,采用接入类似友盟U-APM平台的方式去更快的解决问题是必不可少的。但对于一些小型手机的低版本可能还是会出现ANR的问题,针对类似收集用户行为的情景,可采取进行多种方式去进行收集,例如对于低版本的系统,降低对收集数据的完整性等。




作者:计蒙不吃鱼


相关文章
|
安全 Java 编译器
kotlin面试题
kotlin面试题
784 1
|
5月前
|
数据库 Android开发
Android使用EditText+Listview实现搜索效果(使用room模糊查询)
本文介绍如何在Android中使用EditText与ListView实现搜索功能,并结合Room数据库完成模糊查询。主要内容包括:Room的模糊查询语句(使用`||`代替`+`号)、布局美化(如去除ListView分割线和EditText下划线)、EditText回车事件监听,以及查询逻辑代码示例。此外,还提供了相关扩展文章链接,帮助读者深入了解ListView优化、动态搜索及Room基础操作。
328 65
|
5月前
|
Android开发 开发者
Android动态搜索的简单实现
本文介绍了在Android中实现动态搜索功能的方法,重点讲解了通过`SearchView`与`ListView`结合的方式。文章首先简要提及了`addTextChangedListener`的使用场景,随后详细说明了`SearchView`的相关方法,如`setIconified()`、`setOnQueryTextListener()`等,并通过一个示例展示了如何根据用户输入动态过滤`ListView`中的数据。案例中使用了一个字符串数组作为数据源,通过监听输入变化实现搜索功能。最后提供了完整的源码和布局文件,便于开发者参考和实践。
|
机器学习/深度学习 IDE 开发工具
超越笔记本:JupyterLab 的功能扩展
【8月更文第29天】随着数据科学和机器学习的发展,交互式计算环境的需求也日益增长。Jupyter Notebook 作为这一领域的领头羊,已经得到了广泛的应用。然而,为了满足更加复杂的工作流需求,Jupyter 开发者们推出了 JupyterLab —— 一个下一代的交互式计算环境。本文将探讨 JupyterLab 相对于传统 Jupyter Notebook 的增强功能,并通过具体示例展示这些新特性如何提升工作效率。
515 1
|
机器人 测试技术 Python
作为测试人员,RobotFramework框架真的是必须掌握的吗?
本文探讨了Robot Framework(RF)作为自动化测试框架的重要性,指出虽然RF具有易用性和灵活性,但并非测试人员必须掌握的工具,因为存在许多可替代的自动化测试解决方案。
258 0
作为测试人员,RobotFramework框架真的是必须掌握的吗?
|
存储 XML Java
SharedPreferences详解及其ANR解决方案
SharedPreferences详解及其ANR解决方案
如何做好技术选型
在软件开发领域,几乎每天都有新的技术框架诞生、更新,一些新的概念更是层出不穷,技术选型时,难免让人无从抉择。对于技术选型,我个人有以下几点建议。
1890 0
|
SQL Oracle 关系型数据库
记录:java.sql.SQLException: ORA-00911: 无效字符...【亲测有效】
记录:java.sql.SQLException: ORA-00911: 无效字符...【亲测有效】
616 0
|
Android开发
解决在Android Compose中点击空白处收回软键盘
解决在Android Compose中点击空白处收回软键盘
405 0
|
JavaScript
TypeScript清空数组的4种方法
TypeScript清空数组的4种方法
965 0