Android app會crash的原因及解決方法
android main入口的commonInit()方法內(nèi)處,有這么一句話,
Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
如果沒有這句話,app就不會crash。不信,你往里面看,
public KillApplicationHandler(LoggingHandler loggingHandler) { @Override public void uncaughtException(Thread t, Throwable e) { //捕獲到異常 try { ...... //打印crash日志,展示崩潰彈窗等 // Bring up crash dialog, wait for it to be dismissed ActivityManager.getService().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e)); } catch (Throwable t2) { .... } finally { // Try everything to make sure this process goes away. Process.killProcess(Process.myPid());//殺死進程 System.exit(10); } } }
當異常KillApplicationHandler捕獲到異常,進行完一系列處理(主要是打印crash日志,通知AMS展示crash彈窗等)后,最終會殺死進程,這樣你的app就崩潰了。
既然都崩潰了,自定義異常捕獲器來屏蔽crash真的可行嗎?
肯定有人會說,自定義一個異常捕獲器,來覆蓋掉系統(tǒng)的KillApplicationHandler,然后在捕獲到異常后,不殺進程,app就不會崩潰了,就像下面這樣,
class MainApplication : Application() { override fun onCreate() { super.onCreate() Thread.setDefaultUncaughtExceptionHandler { _, e -> //捕獲到異常,只打印日志,不殺進程 Log.e("MainApplication", "${Thread.currentThread().name} 捕獲到異常:${e.message}") } } }
這其實只是隔壁老王的思路,雖然確實防護住子線程的crash,但是當主線程出現(xiàn)異常時,app還是無法正常運行。這是因為,當UncaughtExceptionHandler捕獲到線程拋出異常的時候,線程在執(zhí)行完uncaughtException()中的處理后,就無法繼續(xù)存活了。如果拋異常的線程是主線程,那就意味著主線程會死掉,這時你即便不殺進程,進程活著也沒有任何意義了,app還是會停止運行。
把android異常捕獲機制在梳理一下,熟悉的同學可以跳過,直接進入下一節(jié)。
- Thread.setCaughtExceptionPreHandler()覆蓋所有線程,會在回調(diào)DefaultExceptionHandler之前調(diào)用;
- Thread.setCaughtExceptionHandler()同樣回覆蓋所有線程,可以在應(yīng)用層被重復調(diào)用,并且每一次調(diào)用后,都會覆蓋上一次設(shè)置的DefaultUncaughtExceptionHandler;
- Thread.currentThread.setUncaughtExceptionHandler(),只可以覆蓋當前線程的異常。如果某個線程存在自定義的UncaughtExceptionHandler,回調(diào)時會忽略全局的DefaultUncaughtHandler。
既然話都說到這份上了,就請接下never crash大招吧。
要想不crash,只能讓線程不要拋出exception,唯此別無他法。如果我們能把一個線程的所有的操作都使用try-catch進行保護,理論上,就能做到app never crash。由于android基于Handler事件驅(qū)動的機制,可以在app啟動時,向主線程中的MessageQueue中提交一個死循環(huán)操作,在這個死循環(huán)中不斷去poll事件,并且將這個死循環(huán)進行try-catch,這樣所有主線程中的異常都會被catch住,從而app就再也不會發(fā)生crash。
private fun openCrashProtected() { Log.d(tag, "openCrashProtected") Handler(Looper.getMainLooper()).post { while (true) { try { Looper.loop() Log.d(tag, "main looper execute loop") } catch (e: Throwable) { //所有主線程中的異常都會被catch住,從而不會發(fā)生crash Log.e(tag, "catch exception: " + e.message) } } } }
有人可能要說了,你這樣catch住主線程的異常了,頁面可能要亂套哇。話雖如此,但你可以在catch中做業(yè)務(wù)保護呀。比如,我這里采取的做法是,關(guān)閉棧頂activity。 解決ActivityLifeCycle,維護一個Activity棧,
private fun registerLifeCycle() { registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { ActivityStack.Instance().push(activity) } override fun onActivityResumed(activity: Activity) { } override fun onActivityStarted(activity: Activity) { } override fun onActivityPaused(activity: Activity) { } override fun onActivityDestroyed(activity: Activity) { ActivityStack.Instance().pop(activity) } override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { } override fun onActivityStopped(activity: Activity) { } }) }
然后當catch住異常時,
//主線程出現(xiàn)異常,關(guān)閉棧頂activity ActivityStack.Instance().curr()?.finish()
github代碼
最后奉上github倉庫代碼,請笑納。
以上就是Android app會crash的原因及解決方法的詳細內(nèi)容,更多關(guān)于Android app crash的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android4.0平板開發(fā)之隱藏底部任務(wù)欄的方法
這篇文章主要介紹了Android4.0平板開發(fā)之隱藏底部任務(wù)欄的方法,結(jié)合實例形式較為詳細的分析了Android隱藏于顯示底部任務(wù)欄的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-11-11Android編程實現(xiàn)畫板功能的方法總結(jié)【附源碼下載】
這篇文章主要介紹了Android編程實現(xiàn)畫板功能的方法,結(jié)合實例形式總結(jié)分析了Android基于自定義View與Canvas類實現(xiàn)畫板功能的具體操作步驟與相關(guān)注意事項,需要的朋友可以參考下2018-02-02myeclipse android環(huán)境搭建圖文教程
在從事android應(yīng)用開發(fā)過程中,搭配環(huán)境是所有開始的第一步,本文將介紹myeclipse android環(huán)境搭建圖文教程,希望可以幫助大家完成android開發(fā)之旅2012-11-11Android開發(fā)之在xml中設(shè)置自定義屬性的方法
下面小編就為大家分享一篇Android開發(fā)之在xml中設(shè)置自定義屬性的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01Flutter?fluro時報錯type?'String'?is?not?a?subty
這篇文章主要介紹了Flutter使用fluro時報錯type?'String'?is?not?a?subtype?of?type?'Queue<Task>'解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-12-12Android 實時監(jiān)測(監(jiān)聽)網(wǎng)絡(luò)連接狀態(tài)變化
這篇文章主要介紹了Android 實時監(jiān)測(監(jiān)聽)網(wǎng)絡(luò)連接狀態(tài)變化的相關(guān)知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-06-06