Android性能优化(二)—— ANR

1 简介

ANRApplication Not Responding),程序长时间无响应。系统长时间无法处理某个操作,就会弹出ANR对话框。

Android系统中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会检测APP的响应时间,如果APP在特定时间无法相应屏幕触摸或键盘输入,或者特定事件没有处理完毕,就会出现ANR

以下四个条件都可以造成ANR发生:

  • InputDispatching Timeout5s内无法响应屏幕触摸事件或键盘输入事件;
  • Service Timeout:前台服务20s内,后台服务在200s内没有执行完毕;
  • BroadcastQueue Timeout:在执行前台广播的onReceive方法时10s没有处理完成,后台为60s
  • ContentProvider TimeoutContentProviderpublish10s内没进行完;

造成以上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异常:

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/(打包导出到桌面)

导出ANR日志

压缩包:

ANR日志

查看:

----- 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()、后台ServiceContentProvider也不要执行太长时间的任务;

参考

Android ANR:原理分析及解决办法
Mac android 导出anr文件
Mac 下导出ANR错误日志
ANR详解-Android

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值