卡頓介紹
我們前文已經在 Android UI卡頓檢測(一)——基於Handler機制的實現方案(線上方案) 中做了介紹。
想要了解的,可以點擊上面鏈接來回顧。
基於WatchDog原理的方案及代碼實現
由於在Android 5.0及以上系統中,默認啓動了SELinux機制,所以我們的App在線上場景中,不能獲得ANR的系統日誌。但是ANR又是我們App穩定性指標的一部分,所以有此方案,配合前文 Android UI卡頓檢測(一)——基於Handler機制的實現方案(線上方案) 來保障App在線上運行中的體驗。
原理
我們想要監控的是UI線程的卡頓,如果卡頓超過了5s,系統就會ANR,那麼我們可以設置一個閾值,比如4s,超過閾值的卡頓,我們把UI線程的運行堆棧上傳到我們的分析後臺。
那麼,如何監控UI線程的長時間卡頓呢?
參考系統的WatchDog原理,我們啓動一個卡頓檢測線程,該線程定期的向UI線程發送一條延遲消息,執行一個標誌位加1的操作,如果規定時間內,標誌位沒有變化,則表示產生了卡頓。如果發生了變化,則代表沒有長時間卡頓,我們重新執行延遲消息即可。
代碼實現
public class WatchDog {
private final static String TAG = "budaye";
//一個標誌
private static final int TICK_INIT_VALUE = 0;
private volatile int mTick = TICK_INIT_VALUE;
//任務執行間隔
public final int DELAY_TIME = 4000;
//UI線程Handler對象
private Handler mHandler = new Handler(Looper.getMainLooper());
//性能監控線程
private HandlerThread mWatchDogThread = new HandlerThread("WatchDogThread");
//性能監控線程Handler對象
private Handler mWatchDogHandler;
//定期執行的任務
private Runnable mDogRunnable = new Runnable() {
@Override
public void run() {
if (null == mHandler) {
Log.e(TAG, "handler is null");
return;
}
mHandler.post(new Runnable() {
@Override
public void run() {//UI線程中執行
mTick++;
}
});
try {
//線程休眠時間爲檢測任務的時間間隔
Thread.sleep(DELAY_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
//當mTick沒有自增時,表示產生了卡頓,這時打印UI線程的堆棧
if (TICK_INIT_VALUE == mTick) {
StringBuilder sb = new StringBuilder();
StackTraceElement[] stackTrace = Looper.getMainLooper().getThread().getStackTrace();
for (StackTraceElement s : stackTrace) {
sb.append(s.toString() + "\n");
}
Log.d(TAG, sb.toString());
} else {
mTick = TICK_INIT_VALUE;
}
mWatchDogHandler.postDelayed(mDogRunnable, DELAY_TIME);
}
};
/**
* 卡頓監控工作start方法
*/
public void startWork(){
mWatchDogThread.start();
mWatchDogHandler = new Handler(mWatchDogThread.getLooper());
mWatchDogHandler.postDelayed(mDogRunnable, DELAY_TIME);
}
}
我們通過調用startWork方法即可開啓卡頓監控,原理和實現步驟,註釋已經非常詳盡了,這裏不做重複解析了。
總結
- 在Android 5.0及以上系統中,默認啓動了SELinux機制,所以我們的App在線上場景中,不能獲得ANR的系統日誌。
- 我們啓動一個卡頓檢測線程,該線程定期的向UI線程發送一條延遲消息,執行一個標誌位加1的操作,如果規定時間內,標誌位沒有變化,則表示產生了卡頓。如果發生了變化,則代表沒有長時間卡頓,我們重新執行延遲消息即可。
- 該方案可以根據自己的需求設置時間間隔。
- 該方案並不能完全檢測到所有的設定條件內的卡頓問題,但可以配合前文的方案來實現交叉覆蓋,基本可以滿足我們的需求。