赞
踩
Appliction Not Responding 直译过来的意思就是应用程序没有响应
原因: 在UI线程上执行一个潜在的耗时操作
场景:
1.KeyDipatchTimeout(5 seconds)-->按键或触摸事件在特定时间内没有响应
2.BroadcastReceiver(10 seconds)-->在特定时间内无法处理完成
3.ServiceTimeout(20 seconds)-->service在特定时间内没有完成
原理:
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
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。