Android开发中难免碰到ANR问题,但是网上关于ANR的文章并不多,那我就写一篇最近工作中碰到ANR的分析过程。
分析过程
- 先查一下网上关于ANR方面的文章,找到的大部分都是说不要主线程执行耗时操作,但是我本来就在子线程里执行的下载操作的。怎么会产生ANR?
- 接着去分析 /data/anr/traces.txt, 好家伙data文件夹不是要root权限 才能访问吗?怎么办不是要我root吧,然后我又去查了资料发现可以用下面的命令导出traces文件
adb shell cat /data/anr/traces.txt > e:\anr.txt
- 打开anr.txt 有1000多行看着都晕,没办法慢慢看吧,看到SharedPreferences想到了我不是在下载的时候存了下载的进度了,猜想应该是它出的问题
| group="main" sCount=1 dsCount=0 obj=0x12dbdac0 self=0xb4256800
| sysTid=4302 nice=0 cgrp=default sched=0/0 handle=0x9d207000
| state=S schedstat=( 11836166912 2318327808 16610 ) utm=552 stm=631 core=1 HZ=100
| stack=0x9c7f2000-0x9c7f4000 stackSize=1036KB
| held mutexes=
at libcore.io.Posix.fsync(Native method)
at libcore.io.BlockGuardOs.fsync(BlockGuardOs.java:143)
at java.io.FileDescriptor.sync(FileDescriptor.java:74)
at android.os.FileUtils.sync(FileUtils.java:152)
at android.app.SharedPreferencesImpl.writeToFile(SharedPreferencesImpl.java:598)
at android.app.SharedPreferencesImpl.access$800(SharedPreferencesImpl.java:51)
at android.app.SharedPreferencesImpl$2.run(SharedPreferencesImpl.java:512)
- locked <@addr=0x131d6bf0> (a java.lang.Object)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
然后去代码里查了一下写的apply 方法,再去网上查了一下apply、和commit的区别
SharedPreferencesImpl源码分析
原来的apply方法是异步执行的,因为下载很快 有进行一次写入操作,在异步写入时导致死锁。
commit是同步的阻塞的。那就把apply改成commit试一下,果然ok了。
TIP
在分析traces.txt首先搜索自己项目包名的堆栈,这样能很快定位问题,如果没有那就要一步一步的看,在关联自己的代码进行联想。应该能解决ANR问题。