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的強,軟,弱,虛四種引用類型。

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

    Android性能調優利器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定位耗時操作。詳情參考:

    BlockCanary原理及使用方式

  • LeakCanary

    Android內存泄漏檢測利器:LeakCanary

以下介紹幾款常用的調試工具和開源庫

facebook stetho

可以動態查看sqlite,並可以執行sql語句動態修改數據庫
可查看sharepreferences數據
對於okhttp可以查看每條連接耗時
可以查看View視圖的層級

其他查看sqlite的方法,用AS把sql數據導出,並利用工具SQLite Expert查看

Android Studio profiler

可動態查看,cpu,內存及網絡使用情況。

timber

https://github.com/JakeWharton/timber

logger

https://github.com/orhanobut/logger

第三方日誌收集,上傳

騰訊 Bugly

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章