1. 程式人生 > >Android App異常檢測及處理

Android App異常檢測及處理

Android App常見的異常可分為三種:ANR,Crash及OOM。當異常發生時如何正確的獲取日誌定位問題非常重要。本文針對這三種異常分別給出了處理建議,並提供了一些日誌收集框架及日誌上傳的思路。

ANR

ANR(Application No Response),俗稱應用卡頓。在Android中所有KeyEvent和TouchEvent都是按照先後順序放入佇列中,依次執行,並且只有當前一個事件執行完畢,才能開始執行下一個事件。每個正在執行的事件都被被儲存在waitQueue中,執行完畢之後從waitQueue中移除。

當用戶觸發一個事件的時候,首先判斷waitQueue是否為空,如果為空,可以立即響應該事件。如果佇列不為空,說明還有事件沒有執行完畢。判斷當前時間和上一個事件響應時間是否大於超時時間(一般5秒,broadCastReceiver 10秒),如果超時,則會通過ActivityManagerService以彈窗的形式通知使用者App無響應。

發生這種異常時,需檢視logcat日誌和traces.txt檔案定位原因。

logcat日誌 通過logcat可定位ANR發生的程式

traces.txt檔案 該檔案需通過adb命令獲取 adb pull /data/anr/traces.txt . 檢視traces.txt檔案,一般檔案開頭可看到導致ANR的堆疊資訊。

android studio的analyze stacktrac工具可協助分析traces.txt檔案

Crash

Crash即程式崩潰,一般是由於程式有未處理的異常導致。這種情況需要抓取程式崩潰的時的堆疊資訊來定位。為了更優雅的來處理程式異常,我們需要捕獲這種未定義的異常,捕獲方式是實現uncaguhtExceptionHandler。捕獲該異常後,我們可以打印出堆疊資訊定位異常發生點,並做一些崩潰處理的操作,如日誌收集並上傳伺服器等。

1.定義自己的異常處理類
public class CrashHandler implements Thread.UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
    //異常出現後會呼叫該函式,請在該函式中做異常處理操作
    }
}

2.在Application中設定預設的異常處理Hanler為自定義Handler
Thread.setDefaultUncaughtExceptionHandler(crashHandler);

OOM

OOM(Out Of Memory),即記憶體溢位。瞭解OOM之前,先熟悉一下Java的強,軟,弱,虛四種引用型別。

如果一個無用物件(不需要再使用的物件)仍然被其他物件持有強引用,造成該物件無法被系統回收,以致該物件在堆中所佔用的記憶體單元無法被釋放而造成記憶體空間浪費,這中情況就是記憶體洩露。當記憶體洩漏超過虛擬機器為APP分配的最大值,就會發生OOM,此時程式會崩潰。

Android程式中可能導致記憶體洩漏的場景:

  • 非靜態內部類導致記憶體洩露

    非靜態內部類(包括匿名內部類)預設就會持有外部類的強引用,當非靜態內部類物件的生命週期比外部類物件的生命週期長時,就會導致記憶體洩露。如:

    Activity中定義Handler,Handler會預設持有activity的強引用。當Activity生命週期結束但Handler還有未完成的任務時。

    Activity開啟執行緒Thread,AsyncTask,建立匿名內部類物件,預設就隱式的持有外部Activity的強引用。當Activity生命週期結束時,執行緒任務還未結束。

//如果要使用內部類,但又要規避記憶體洩露,需採用靜態內部類+弱引用的方式
private static class MyHandler extends Handler {

        private WeakReference<MainActivity> activityWeakReference;

        public MyHandler(MainActivity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = activityWeakReference.get();
            if (activity != null) {
                if (msg.what == 1) {
                    //通過activity.xxx來呼叫activity的變數和方法
                }
            }
        }
    }
  • 靜態變數導致記憶體洩露

    靜態變數儲存在方法區,它的生命週期從類載入開始,到整個程序結束。一旦靜態變數初始化後,它所持有的引用只有等到程序結束才會釋放。如果靜態變數持有了Activity的強引用,比如持有了Activity的context會導致,會導致Activity洩漏。

  • 廣播使用後未取消,屬性動畫未取消。

  • 檔案流,網路流,資料流等使用後未正常關閉。

只要能夠避免以上情況的發生,那就可以避免大多數的記憶體洩漏。

檢測工具

  • StrictMode

    StrictMode意思為嚴格模式,是用來檢測程式程式碼中違例情況的開發者工具。可以檢查程式中的ANR和記憶體洩漏。它能在開發階段給你直觀的提示,並需要在Release版本中關掉。StrictMode有兩個策略:

    ThreadPolicy 檢查主執行緒耗時操作磁碟IO,Network,其他邏輯耗時

    VmPolicy 檢查Activity,Closable,sqlite物件洩漏

  • Android Lint

    Lint 是 Android studio 自帶的靜態程式碼分析工具,能夠幫助分析程式碼中的錯誤。使用入口頂部選單Analyze -> Inspect Code。掃描完成後檢視Performance 項,裡面會有一些程式碼洩漏的建議和其他優化建議。

  • BlockCanary

    BlockCanary是由markzhai大神釋出在Github上的一個開源工具,該工具通過計算Looper事件迴圈流程中,事件執行前和事件執行完成後的時間差來檢查該行為是否發生了卡頓。能夠很好的幫助App定位耗時操作。詳情參考:

以下介紹幾款常用的除錯工具和開源庫

可以動態檢視sqlite,並可以執行sql語句動態修改資料庫 可檢視sharepreferences資料 對於okhttp可以檢視每條連線耗時 可以檢視View檢視的層級

其他檢視sqlite的方法,用AS把sql資料匯出,並利用工具SQLite Expert檢視

Android Studio profiler

可動態檢視,cpu,記憶體及網路使用情況。

timber
logger
第三方日誌收集,上傳

騰訊 Bugly