我是靠谱客的博主 顺心镜子,最近开发中收集的这篇文章主要介绍Android中ANR的监测与定位,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、原理

1. ANR监测原理

判断ANR的方法其实很简单,我们在子线程里向主线程发消息,如果过了固定时间后,消息仍未处理,则说明已发生ANR了。

看懂了直接看2,没看懂继续看。

Android应用程序的所有交互操作和响应,都是通过主线程的消息机制来进行的。例如当用户点击了某个Button,系统会向主线程发送消息,主线程的Looper从主线程消息队列中取出消息并处理,处理完当前消息,主线程Looper再去取出下一个消息。当主线程做了耗时的任务,主线程的Looper就无法从消息队列中取出新的消息,所表现出的就是程序卡顿,甚至是ANR。同理,我们在子线程往主线程发送一个消息,要是消息无法得到及时处理,那说明程序发生ANR了。


2. 定位耗时操作的原理

当程序ANR后,我们可以通过主线程Looper拿到主线程Thread,然后通过getStackTrace拿到主线程当前的调用栈,从而定位到发生ANR的地方,定位到耗时操作。


二、代码实现


1. 首先我们定义一个线程,用来监测主线程。

在该线程中,我们首先给主线程发送消息,然后睡眠指定时间,之后监测消息是否被处理,若未被处理,则抛出ANR异常。
为什么叫ANRWatchDog:了解嵌入式的人对看门狗应该很熟悉,在嵌入式中,看门狗定时器在程序跑飞时,可定时复位程序,而我们必须定期喂狗(将定时器清零),表示程序正常运行。
watchDogHandler:用来给主线程发送消息,并处理消息。

lastTimeTick/timeTick:用来判断消息是否被处理




public class ANRWatchDog extends Thread {
public static final int MESSAGE_WATCHDOG_TIME_TICK = 0;
/**
* 判定Activity发生了ANR的时间,必须要小于5秒,否则等弹出ANR,可能就被用户立即杀死了。
*/
public static final int ACTIVITY_ANR_TIMEOUT = 2000;
private static int lastTimeTick = -1;
private static int timeTick = 0;
private Handler watchDogHandler = new android.os.Handler() {
@Override
public void handleMessage(Message msg) {
timeTick++;
timeTick = timeTick % Integer.MAX_VALUE;
}
};
@Override
public void run() {
while (true) {
watchDogHandler.sendEmptyMessage(MESSAGE_WATCHDOG_TIME_TICK);
try {
Thread.sleep(ACTIVITY_ANR_TIMEOUT);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果相等,说明过了ACTIVITY_ANR_TIMEOUT的时间后watchDogHandler仍没有处理消息,已经ANR了
if (timeTick == lastTimeTick) {
throw new ANRException();
} else {
lastTimeTick = timeTick;
}
}
}
}


2. 启动这个线程

为了确保该线程在程序启动后第一时间运行,因此自定义一个Application,在onCreate中开启这个线程。


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


 3. 定义发生ANR时的操作,这里是自定义了一个异常,ANR时抛出。


	public class ANRException extends RuntimeException {
public ANRException() {
super("应用程序无响应,快来改BUG啊!!");
Thread mainThread = Looper.getMainLooper().getThread();
setStackTrace(mainThread.getStackTrace());
}
}


4. 在Activity中模拟耗时操作

在我的demo中是直接Thread.sleep(10000),让主线程睡10秒。


5. Manifest文件中,注册Activity,配置Application





三、运行结果

程序过了几秒后抛出了ANRException,如下图所示。箭头指的地方就是产生ANR的地方(耗时操作),在本程序中是Thread.sleep。





代码下载戳这里



最后

以上就是顺心镜子为你收集整理的Android中ANR的监测与定位的全部内容,希望文章能够帮你解决Android中ANR的监测与定位所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部