Android UI卡頓檢測(二)——基於WatchDog原理的方案(線上方案)

卡頓介紹


我們前文已經在 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方法即可開啓卡頓監控,原理和實現步驟,註釋已經非常詳盡了,這裏不做重複解析了。

總結


  1. 在Android 5.0及以上系統中,默認啓動了SELinux機制,所以我們的App在線上場景中,不能獲得ANR的系統日誌。
  2. 我們啓動一個卡頓檢測線程,該線程定期的向UI線程發送一條延遲消息,執行一個標誌位加1的操作,如果規定時間內,標誌位沒有變化,則表示產生了卡頓。如果發生了變化,則代表沒有長時間卡頓,我們重新執行延遲消息即可。
  3. 該方案可以根據自己的需求設置時間間隔。
  4. 該方案並不能完全檢測到所有的設定條件內的卡頓問題,但可以配合前文的方案來實現交叉覆蓋,基本可以滿足我們的需求。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章