Android「應用已停止運行」是什麼原理?

想理解一下這類錯誤出現的原因以及相關機制。


其實就是程序由於某些原因出錯了,可能是代碼 BUG 也可能是系統和環境因素導致的。

例如你的某個 App 需要通過伺服器獲取數據,但是你的手機網路有問題導致一直獲取不到,造成網路連接超時。如果代碼中未對「超時」這個可能發生的情況進行處理的話,那麼「出現網路請求超時」這個現象就屬於未捕獲的異常。異常就是指的超時這個行為,未捕獲指的未對這個行為進行處理。

而 Android 中程序一旦出錯,就會統一的彈出一個「應用已停止運行」,然後結束或者重啟應用程序。

單看這個彈窗是無意義的,如果你想看到實際細節,你需要深入輸出的日誌找到具體原因。這時候就需要用 logcat。

logcat 查看日誌,需要先讓設備成功進行 adb 連接以後。然後:

adb logcat

當然,由於已經確定要看的是已經崩潰的應用,那麼我們過濾日誌 Tag 類型為 Error 即可:

adb logcat *:E

再由於我們通常是知道崩潰是那個應用,所以我們可以繼續指定應用過濾。例如我自己開發的一個 App 包名是 io.bluerain.tweaks,假設我不是開發者,我只能通過包名過濾。

網上有一種方法是利用 Android 內置的 ps 命令獲取進程,然後用 grep 過濾和 cut 截取到 pid,再由 pid 過濾日誌。這樣間接的實現包名過濾的手段:

adb logcat *:E | grep -F "`adb shell ps | grep io.bluerain.tweaks | cut -c14-18`"

先運行應用,然後輸入上面的命令。再重現一次應用崩潰,就可以看到很少量的日誌輸出,其中包含崩潰詳情,例如我這邊是出現的異常是:

01-19 18:43:38.110 13189 13225 E AndroidRuntime: FATAL EXCEPTION: Thread-6
01-19 18:43:38.110 13189 13225 E AndroidRuntime: Process: io.bluerain.tweaks, PID: 13189
01-19 18:43:38.110 13189 13225 E AndroidRuntime: java.io.FileNotFoundException: /sdcard/recovery.checker.img (Permission denied)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at java.io.FileInputStream.open0(Native Method)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at java.io.FileInputStream.open(FileInputStream.java:200)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at java.io.FileInputStream.&(FileInputStream.java:150)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at kotlin.io.FilesKt__FileReadWriteKt.readBytes(Unknown Source:8)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at io.bluerain.tweaks.d.b$d.a(Unknown Source:100)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at io.bluerain.tweaks.d.b$d.invoke(Unknown Source:0)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at io.bluerain.tweaks.a.e.run(Unknown Source:2)
01-19 18:43:38.110 13189 13225 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764)

從 *Exception 的冒號後面看異常消息,發現是無權訪問 SD 卡。所以它就是導致該應用已停止運行的原因。

另外,這個跟 ANR 無關。ANR 是 Application not Responding 的簡寫,也就是「應用未響應」,它通常跟異常、BUG 等都無關,二者完全不是一回事兒。


出現了未捕獲的異常


修正下,問題看錯了,前面回答成 ANR 了,應用已停止運行是執行的代碼發生未捕獲異常退出了,這種通常會伴隨閃退,可以抓下日誌看看異常信息即可~~

============下面是 ANR 彈框的解釋=================

這類錯誤一般稱為ANR(APP 無響應),原因是 UI 線程被阻塞,要理解這個首先要有線程的概念。

理論上CPU 處理程序都是順序執行的,100條代碼,cpu 會逐條執行,遇到跳轉語句則停止當前的處理,然後轉去執行跳轉目標的代碼,執行完後返回接著執行(當然事實上不是,因為有分支預測之類的技術)。如果遇到一些耗時操作,比如等待用戶輸入之類的,則 cpu 會停下,直到用戶完成輸入後,cpu 收到數據,才接著執行下去,這種現象稱為阻塞。

但有的時候,我們往往需要程序能非同步執行代碼,即在效果上實現 cpu 能同時執行多個代碼塊,比如,在等待用戶輸入的時候,還能放個音樂看個小黃書什麼的,為了實現這種非同步效果,操作系統為我們引入了進程這個概念。

進程本質上就是一個載入到內存的可執行程序,每當用戶啟動一個程序,代碼就會被載入內存,稱為一個進程,用戶可以同時啟動多個程序,這樣就會有多個進程,進程是可以同時被 CPU 執行的,當一個進程的代碼發生阻塞,操作系統會讓 cpu 自動轉去執行另外一個進程。而在一般情況下,操作系統則會按照進程不同的優先順序,讓 CPU在不同的進程間來回切換執行。

有了進程後人們發現,在很多情況下,光有進程間的非同步執行還遠遠不夠,我們往往還需要可執行程序內也有非同步執行代碼的功能,比如視頻播放器程序,我在 cpu 全力從磁碟載入解碼渲染視頻的時候,顯然不能阻塞用戶的輸入操作比如按停止鍵,在這種需求下,於是又有了線程這個概念,線程最早被稱為次級進程,也就是進程內的進程,後面不知道誰覺得這種說法有點2B,於是改為了線程。

線程出現後,每個可執行程序都會有一個主線程,也就是 main 方法所在的代碼流程,然後開發人員可以通過調用系統介面開啟新的線程,多個線程在效果上是可以同時執行的,這樣,編程的方式就徹底改變了,比如前面提到的視頻播放器程序,我可以在程序中開啟一個線程負責從磁碟載入解碼視屏,然後另開一個線程,負責將解碼的視頻畫到屏幕上,然後再另開一個線程專門接收用戶輸入,然後這幾個線程是同時執行的,這樣就解決了上述的問題。

好了,然後我們回過頭來看 ANR,每個安卓 APP 中都有一個 UI 線程,專門負責繪製界面,但有的時候,由於一些不良的代碼習慣,往往會將一些阻塞性的操作寫到 UI 線程上,比如死循環,這樣就會導致 UI 線程被阻塞(手機。。。手機它卡住了,點了沒反應),安卓系統有個機制就是當 UI 線程被阻塞超過15秒(不同版本不一樣,大致這個時間),就會認定這個 APP 掛了,然後系統就會彈出 ANR 彈框告知用戶,這破 APP 沒響應了,關了吧,就是這麼回事。


Crach,系統崩潰,就會彈出這個窗口。

都是由於java程序拋出Exception後沒有捕獲出現的。

但是現在有很多廠商在系統層屏蔽了這個頁面,因此表現為閃退。

很多答主提到的ANR是另外一種情況,通常是由於阻塞超過Android系統認為的安全時間後引導用戶強行關閉的頁面。

最後再說一點吧,crach比ANR的bug好解~


Crash 除了java層出現未捕獲異常,也有可能是native層出現段錯誤,fatal addr,crash一般比較容易定位到錯誤

ANR 是某個線程block在處理某個函數超過5秒了,這時候再做UI操作就會anr。native層一般是消息處理線程,某個消息發出後沒有及時得到響應,導致message queue里其他消息都block住了。這個可以看log里anr附近哪個線程隔了五秒都沒有log打出來,anr一般會打出trace log


我從開發者角度通俗的說一下吧,這種問題一般就是某個方法拋出了異常而沒處理(可以理解為程序出了程序員意料之外的錯誤),或者是I/O方法被阻塞,在主線程中進行了耗時請求等,這幾個是最常遇到的。

尤其是在內存不足時,有的方法就會因為無法分配足夠的內存被阻塞,時間長了就會被系統判定為無響應。


提醒該程序的開發者「該加班了」


一般都是空指針異常,抓log看看


未捕獲的異常


應該是異常,沒有被捕獲進而報錯了吧。

建議使用logcat,可以查找對應的錯誤類型和發生錯誤的地方。

這裡有一個ANR處理的文章,可以看一下。當然後面也寫了force close的情況。根據你問題的提示一般就是force close了。

https://github.com/francistao/LearningNotes/blob/master/Part1/Android


推薦閱讀:

Linux下交叉編譯出的so庫依賴libstdc++.so.6的問題?
如何評價Zealer安卓版客戶端?
Github 上有哪些值得學習的 gradle 開源插件?
關於豌豆莢(類似應用)和國內第三方 Android 應用商店的思考,不知道是否正確?
小白求問!安卓root之後都能幹嘛!?

TAG:Android開發 | Android |