1 简介
ANR
(Application Not Responding
),程序长时间无响应。系统长时间无法处理某个操作,就会弹出ANR
对话框。
在Android
系统中,ActivityManagerService
(简称AMS
)和WindowManagerService
(简称WMS
)会检测APP
的响应时间,如果APP
在特定时间无法相应屏幕触摸或键盘输入,或者特定事件没有处理完毕,就会出现ANR
。
以下四个条件都可以造成ANR
发生:
InputDispatching Timeout
:5s
内无法响应屏幕触摸事件或键盘输入事件;Service Timeout
:前台服务20s
内,后台服务在200s
内没有执行完毕;BroadcastQueue Timeout
:在执行前台广播的onReceive
方法时10s
没有处理完成,后台为60s
;ContentProvider Timeout
:ContentProvider
的publish
在10s
内没进行完;
造成以上ANR
的首要原因就是在主线程中做了太多的耗时操作,例如读写文件,访问数据库,网络请求等。因此,尽可能的避免在主线程中做耗时操作。
2 ANR
分析
在MainActivity
中生成一个按钮跳转到ANRActivity
中,在后者的onCreate()
中主线程休眠20s
:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_anr_test);
// 这是Android提供线程休眠函数,与Thread.sleep()最大的区别是
// 该使用该函数不会抛出InterruptedException异常。
SystemClock.sleep(20 * 1000);
}
在进入ANRActivity
后黑屏一段时间,再过几秒,弹出了ANR
异常:
日志打印:
2022-06-26 07:57:59.031 559-8280/system_process E/ActivityManager: ANR in com.example.kotlintest (com.example.kotlintest/.ui.MainActivity)
PID: 8213
Reason: Input dispatching timed out (3aa19cd com.example.kotlintest/com.example.kotlintest.ui.MainActivity (server) is not responding. Waited 5001ms for FocusEvent(hasFocus=false))
Parent: com.example.kotlintest/.ui.MainActivity
指令:adb shell ls /data/anr/
(查看日志文件) adb pull /data/anr/[文件名] ~/Desktop/
(导出日志)
adb bugreport ~/desktop/
(打包导出到桌面)
压缩包:
查看:
----- pid 8213 at 2022-06-26 07:57:57.303937000+0800 -----
Cmd line: com.example.kotlintest // 最新发生ANR的进程(包)名
"main" prio=5 tid=1 Sleeping // 产生ANR的原因Sleeping
| group="main" sCount=1 ucsCount=0 flags=1 obj=0x71e37bb8 self=0x7b2e7961b380
| sysTid=8213 nice=-10 cgrp=top-app sched=0/0 handle=0x7b2fc66524f8
| state=S schedstat=( 1265272404 141474997 421 ) utm=66 stm=59 core=0 HZ=100
| stack=0x7ffc3fe30000-0x7ffc3fe32000 stackSize=8188KB
| held mutexes=
at java.lang.Thread.sleep(Native method)
- sleeping on <0x0e6d0d57> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:451)
- locked <0x0e6d0d57> (a java.lang.Object)
at java.lang.Thread.sleep(Thread.java:356)
at android.os.SystemClock.sleep(SystemClock.java:131)
at com.example.kotlintest.ANRActivity.onCreate(ANRActivity.kt:11) // 产生ANR的包名以及具体行数
at android.app.Activity.performCreate(Activity.java:8051)
at android.app.Activity.performCreate(Activity.java:8031)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1329)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3608)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3792)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2210)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
3 造成ANR
的原因及解决办法
上面例子只是由于简单的主线程耗时操作造成的ANR
,造成ANR
的原因还有很多:
- 主线程阻塞或主线程数据读取,尽量避免死锁的出现,使用子线程来处理耗时操作或阻塞任务,不要滥用
SharedPreference
; CPU
满负荷,I/O
阻塞,文件读写或数据库操作放在子线程异步操作;- 内存不足,
AndroidManifest.xml
文件<applicatiion>
中可以设置android:largeHeap = "true"
,以此增大APP
使用内存。不过不建议使用此法,从根本上防止内存泄漏,优化内存使用才是正道; - 各大组件
ANR
:各大组件生命周期中也应避免耗时操作,注意BroadcastReciever.onRecieve()
、后台Service
和ContentProvider
也不要执行太长时间的任务;