响应速度优化的核心思想是避免在主线程中做耗时操作,耗时操作可以采用异步的方式去执行。
响应速度过慢更多的体现在Activity的启动速度上面,如果在主线程中做太多的事情,会导致Activity在启动时出现黑屏现象,甚至出现ANR;
ANR产生原因:
Android规定,Activity如果5s之内无法响应屏幕触摸事件或者键盘输入事件就会出现ANR,BroadcastReceiver如果10s之内还未执行完操作也会出现ANR,执行Service的各个生命周期函数时超过20s;
根本原因:
1.应用进程自身原因:主线程阻塞,挂起,死循环,执行耗时操作等;
2.其他进程引起,如其他进程CPU占用率过高,导致当前进程无法抢占到CPU时间片,常见的问题如文件读写频繁,io进程CPU占用率过高,导致当前应用出现ANR
ANR定位:
如果在实际开发中碰到了ANR,如何去定位?
其实当一个进程发生ANR了以后,系统会在/data/anr目录下创建一个文件traces.txt,通过分析这个文件就能定位出ANR的原因;
分析流程:
1.当出现ANR后,导出traces文件,即
adb pull /data/anr/traces.txt
2.查看分析traces文件
traces文件的内容,是以线程为单位,一条条的出现的,如在主线程中开启了另一个线程,这时的traces文件中就会有这两个线程的追踪内容;
trace内容解析:
"main",表示线程名;
tid=1,tid表示线程的id;
trace的head后面会紧跟ANR产生的原因,有些时候原因表述的不够直接,可能会指向其他线程,此时就要根据原因表述中的其他线程的id去其他线程中去寻找原因;
常见ANR的出现场景:
1.主线程执行耗时操作,如主线程sleep了30s;
2.子线程和主线程抢占同步锁,而子线程执行耗时操作,导致主线程等待子线程所持有的锁时间过长;
解决ANR的办法:
常见办法是不在主线程中做耗时操作,如
1.主线程需要做耗时操作时,比如网络访问、数据库操作及位图变换等,必须启动一子线程处理,并利用handler来更新UI;
2.子线程尽量使用Android提供的API,比如HandlerThread,AsyncTask,AsyncQueryHandler等,这些API都提供了对于线程的系统级管理。如果应用直接使用Thread实现的话,则需要对这些子线程进行显式管理,比如线程池及线程周期的控制,以防止系统资源和内存泄漏;
3.Broadcast Receiver中如果有耗时操作,可以放到service中来处理;
4. 在后台子线程处理耗时操作时,为了提高用户体验,可以在前台界面显示某些动画或者progress bar;