Android ANR问题定位

  1. 什么是ANR
Appliction Not Responding 直译过来的意思就是应用程序没有响应
  1. ANR的产生原因, 及场景
原因: 在UI线程上执行一个潜在的耗时操作

场景:
1.KeyDipatchTimeout(5 seconds)-->按键或触摸事件在特定时间内没有响应
2.BroadcastReceiver(10 seconds)-->在特定时间内无法处理完成
3.ServiceTimeout(20 seconds)-->service在特定时间内没有完成
  1. 如何监测ANR
原理:
Android应用程序的所有交互操作和响应,都是通过主线程的消息机制来进行的。
例如当用户点击了某个Button,系统会向主线程发送消息,主线程的Looper从主线程消息队列中取出消息并处理,处理完当前消息,主线程Looper再去取出下一个消息。
当主线程做了耗时的任务,主线程的Looper就无法从消息队列中取出新的消息,所表现出的就是程序卡顿,甚至是ANR。
同理,我们在子线程往主线程发送一个消息,要是消息无法得到及时处理,那说明程序发生ANR了。

思路:
在子线程里向主线程发消息,如果过了固定时间后,消息仍未处理,则说明已发生ANR了
当程序ANR后,我们可以通过主线程Looper拿到主线程Thread,然后通过getStackTrace拿到主线程当前的调用栈,从而定位到发生ANR的地方,定位到耗时操作

定义一个线程, 用来监测主线程

class WatchDogThread : Thread() {
    companion object {
        val MESSAGE_WATCHDOG_TIME_TICK = 0
        /**
         * 判定Activity发生了ANR的时间,必须要小于5秒,否则等弹出ANR,可能就被用户立即杀死了。
         */
        val ACTIVITY_ANR_TIMEOUT = 2000
        private var lastTimeTick = -1
        private var timeTick = 0
    }

    private val watchDogHandler = object : android.os.Handler() {
        override fun handleMessage(msg: Message) {
            timeTick++
            timeTick %= Integer.MAX_VALUE
        }
    }

    override fun run() {
        while (true) {
            watchDogHandler.sendEmptyMessage(MESSAGE_WATCHDOG_TIME_TICK)
            try {
                Thread.sleep(ACTIVITY_ANR_TIMEOUT.toLong())
            } catch (e: InterruptedException) {
                e.printStackTrace()
            }

            // 如果相等,说明过了ACTIVITY_ANR_TIMEOUT的时间后watchDogHandler仍没有处理消息,已经ANR了
            if (timeTick == lastTimeTick) {
                throw ANRException()
            } else {
                lastTimeTick = timeTick
            }
        }
    }
}

在Application启动监测线程

public class MyApplication extends Application {  
    @Override  
    public void onCreate() {  
        new WatchDogThread().start();
        super.onCreate();  
    }  
} 

当监测到发生ANR时,抛出一个自定义异常

class ANRException : RuntimeException("应用程序无响应,快来改BUG啊!!") {
    init {
        val mainThread = Looper.getMainLooper().thread
        stackTrace = mainThread.stackTrace
    }
}

猜你喜欢

转载自blog.csdn.net/APTX8899/article/details/88648925