捕獲程序Crash,讓你的APP告別閃退

文章最先發佈於個人微信公衆號 Android_De_Home 中,歡迎你們掃描下面二維碼關注微信公衆獲取更多知識內容。
能夠隨意轉載,但請務必註明出處!java

爲何出現這種方法

當APP在線程中跑出了異常就會致使APP crash。好比咱們最多見的NullPointerException空指針異常。有些時候咱們不但願這種異常致使咱們的APP crash,尤爲是在debug狀態下,程序很大的時候,編譯運行一次也不容易,debug的時候好不容易程序啓動起來了,發生了crash就不能debug執行了,有時候會很耽誤開發。全部有了這個自定義的異常處理。它能夠捕獲你的異常,使程序不會crash,這樣就能夠繼續調試了。android

具體操做介紹

首先介紹Thread.UncaughtExceptionHandler

UncaughtExceptionHandler文檔

文檔說明:當一個線程忽然的由於沒有捕獲到的異常而中止的時候會由這個接口來處理。當一個線程因爲沒有捕獲的異常而終止的時候,Java虛擬機將查詢這個線程經過UncaughtExceptionHandler的getUncaughtExceptionHandler。並將調用uncaughtExcetion方法,而且把這個線程和異常做爲參數傳遞過去。若是一個線程沒有他的UncaughtExceptionHandler設置, 那麼它的ThreadGroup對象做爲它的UncaughtExceptionHandler。若是ThreadGroup對象沒有特別的處理異常要求,它能夠調用getDefaultUncaughtExceptionHandler。即系統默認的的 UncaughtExceptionHandler。git

簡單來講UncaughtExceptionHandler就是用於在線程中當一些系統沒有捕獲的異常發生的時候來處理這些異常的。你可使用系統默認的處理方式,你也能夠經過Thread.setDefaultUncaughtExceptionHandler()方法設置你本身定義的異常處理。github

uncaughtException_method

注意Thread.setDefaultUncaughtExceptionHandler(CustomUncaughtExceptionHandler)後,只能保證當在你的程序中若是crash沒有發生在UI線程(主線程)中而是在別的線程中的時候,這個時候APP是不會出現崩潰的現象的。若是在主線程中出現crash後,APP仍是會崩潰的。微信

進一步防止程序出現Crash

開頭已經說了,有不少時候雖然咱們的APP會由於各類問題閃退,可是在更多的時候咱們是不但願,個人APP閃退的這就出現了下面的方法。app

首先說明這種方法在Activity初始化的時候可能會致使你的APP出現相似ANR的狀況(其實並非ANR,只是狀態看起來像,形成的緣由是由於Activity尚未完成初始化,也就是生命週期尚未執行完畢就遇到異常了,致使了頁面無法顯示,因此在正式發佈的APP中仍是要慎重使用)ide

如何使用呢?須要和你的後臺商量好,在程序中作好標誌控制該不應使用ExceptionHandler來處理。若是你的程序某個地方出現大量crash的時候,而這個功能是在Activity初始化後(多是因爲點擊某個按鈕觸動的問題)這個時候你就能夠用ExceptionHandler來處理了,讓用戶在點擊這個按鈕後,不至於程序崩潰掉。函數

核心代碼:oop

new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {

                while (true) {
                    try {
                        Looper.loop();
                    } catch (Throwable throwable) {
                       
                            
								               
                    }
                }
            }
        });
複製代碼

經過Handler向主線程的queue中添加一個Runnabel(此處new Handler()裏面傳參數Looer.getMainLooper()就是爲了是向主線程的queue中添加,若是不傳這個參數就是默認的了)當主線程執行到咱們發送的這個Runnable的時候就會進入咱們的while死循環,若是while內部是空的話就會形成代碼卡死在這裏致使ANR,可是咱們在while中調用了Looper.loop(),這就使得咱們的主線程又開始工做了,不斷的從queue中獲取Message執行(其實Android的機制就是這樣的不斷的從主線程的queue中獲取message而且執行)。這樣就能夠保證之後主線程的全部異常都會從咱們手動調用的Looper.loop()處拋出了。post

下面分析一下爲何這樣就能夠保證主線程的全部異常都會從咱們手動調用的Looper.loop()處拋出。

ActivityThread_main()

首先看主線程的源碼,個人主線程都是在main()函數裏面開始執行的,就像Java同樣,這裏是入口。咱們能夠看到在main函數中調用了Looper.loop()。

Looper.loop()

Looper.loop()方法的源碼,在這裏就很明顯了,咱們能夠看到在這個方法中有一個for(;;)死循環,不斷的從queue中獲取message執行。因此咱們的方法就變成了

for(;;){
            Message msg = queue.next();
            //若是msg是咱們post過來的Runnable就會執行下面的代碼了
            while(true){
                try{
                    Looper.loop();(的本質就是 for(;;){.....})
                }catch(....){
                    ........

                }

            }

        }
複製代碼

因此當出現異常的時候就會拋出了。因此這樣作的話就能夠保證全部主線程中的異常能夠被捕獲了,單純這樣作的話,子線程中若是出現問題的話仍是會crash的,因此就要加上Thread.setDefaultUncaughtExceptionHandler()了。

原理基本就介紹完了,結合寫的代碼(代碼裏面有詳細的使用註釋)看會更清晰一些。代碼地址和使用方法點擊 這裏

參考:https://github.com/android-notes/Cockroach ,謝謝!


關注公衆號,及時獲取推送
關注公衆號,及時獲取推送
相關文章
相關標籤/搜索