ANR 是 Android 應用程序中的 "Application Not Responding" 的縮寫,中文意思是 "應用程序無響應"。這是當應用程序在 Android 系統上運行時,由于某種原因不能及時響應用戶輸入事件或執行一個操作,導致界面無法更新,系統彈出對話框通知用戶應用程序未響應,給用戶提供了等待它響應或是直接關閉的選項。
當應用程序發生ANR 時,Android 系統會在設備的日志文件中記錄相關信息,這個文件包含了在 ANR 發生時的各個線程的調用堆棧(路徑:/data/anr/traces.txt)
但是 /data/anr/ 路徑只有 root 權限才能夠進行訪問,在非 root 權限的情況下需要 adb 命令導出相關的日志文件后篩選查看 ANR 的日志信息
舉個例子,故意寫個 ANR:
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)findViewById<Button>(R.id.btn).setOnClickListener {Thread.sleep(100000)}}
}
連續點擊按鈕,等待系統 ANR 的彈框,點擊確認。
?將設備的診斷信息日志導出到電腦上(路徑默認是adb的路徑):
adb bugreport
想到電腦上的指定路徑也可以配置:
adb bugreport D:\log.zip
?把導出的 zip 包解壓縮后打開:
?日志文件比較多,ANR 所在的文件目錄在:\FS\data\anr
這里面就包含了每一次發生 ANR 時的日志信息,日期時間都能看到
找到對應時間點的 ANR 日志用 txt 打開
里面的信息非常多,使用 Ctrl + F?搜索主線程相關的信息: "main" prio=5 tid=1
這樣子就能夠快速定位到主線程相關的信息了
首先跟在主線程后面的是狀態,常見的有這幾種狀態:
Native:正在執行 JNI 本地函數(主線程空閑時執行的 nativePollOnce 也屬于此)
Runnable:線程正在 Java 虛擬機中執行(可能正在進行耗時操作)
Sleeping:線程正在睡眠(通常是調用了 Thread.sleep() )
Blocked:線程被阻塞(等待監視器鎖的釋放)
在我舉的例子中,主線程就是處于?Sleeping 狀態,我們就可以往下看日志信息找到調用的堆棧,從而定位到代碼進行具體的優化
應用在線上的數據中里,ANR 并不完全由應用產生,也有可能由系統原因導致(比如內存不足、其他應用CPU搶占等),即便如此,我們還是需要盡量避免在應用層產生?ANR