1、原理android
1. ANR監測原理ide
判斷ANR的方法其實很簡單,咱們在子線程裏向主線程發消息,若是過了固定時間後,消息仍未處理,則說明已發生ANR了。oop
看懂了直接看2,沒看懂繼續看。.net
Android應用程序的全部交互操做和響應,都是經過主線程的消息機制來進行的。例如當用戶點擊了某個Button,系統會向主線程發送消息,主線程的Looper從主線程消息隊列中取出消息並處理,處理完當前消息,主線程Looper再去取出下一個消息。當主線程作了耗時的任務,主線程的Looper就沒法從消息隊列中取出新的消息,所表現出的就是程序卡頓,甚至是ANR。同理,咱們在子線程往主線程發送一個消息,要是消息沒法獲得及時處理,那說明程序發生ANR了。線程
2. 定位耗時操做的原理3d
當程序ANR後,咱們能夠經過主線程Looper拿到主線程Thread,而後經過getStackTrace拿到主線程當前的調用棧,從而定位到發生ANR的地方,定位到耗時操做。blog
2、代碼實現隊列
1. 首先咱們定義一個線程,用來監測主線程。get
在該線程中,咱們首先給主線程發送消息,而後睡眠指定時間,以後監測消息是否被處理,若未被處理,則拋出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
3、運行結果
程序過了幾秒後拋出了ANRException,以下圖所示。箭頭指的地方就是產生ANR的地方(耗時操做),在本程序中是Thread.sleep。