一個簡單的看門狗,用於檢測 Android ANR(應用程式無響應)。
目前 Android 應用程式無法捕獲並報告 ANR 錯誤。
如果您的應用程式不在 Play 商店中(因為您仍在開發它,或者因為您以不同的方式分發它),則調查 ANR 的唯一方法是提取檔案 /data/anr/traces.txt。
此外,我們發現使用 Play 商店不如選擇我們自己的錯誤追蹤服務有效。
android bug tracker 中有一個問題條目描述了這個缺陷,請隨意給它加註星號;)
它設定一個「看門狗」計時器,用於偵測 UI 執行緒何時停止回應。當它發生時,它會引發所有執行緒堆疊追蹤的錯誤(首先是主執行緒)。
是的!我很高興你問:這就是它最初開發的原因!
當這引發錯誤時,崩潰處理程序可以攔截它並按需要的方式處理它。
已知的工作崩潰報告者包括:
setReportMainThreadOnly()
)它沒有理由不與[在此處插入您最喜歡的崩潰報告系統]一起使用。
看門狗是一個簡單的線程,它在循環中執行以下操作:
在app/build.gradle
檔案中新增:
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
在您的應用程式類別的onCreate
中,新增:
new ANRWatchDog (). start ();
下載最新的jar包
將jar放到專案的libs/
目錄下
ANRError
堆疊追蹤有點特殊,它具有應用程式中運行的所有執行緒的堆疊追蹤。因此,在報告中,每個caused by
並不是先前異常的原因,而是不同執行緒的堆疊追蹤。
這是一個死鎖範例:
FATAL EXCEPTION: |ANR-WatchDog|
Process: anrwatchdog.github.com.testapp, PID: 26737
com.github.anrwatchdog.ANRError: Application Not Responding
Caused by: com.github.anrwatchdog.ANRError$_$_Thread: main (state = WAITING)
at testapp.MainActivity$1.run(MainActivity.java:46)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
Caused by: com.github.anrwatchdog.ANRError$_$_Thread: APP: Locker (state = TIMED_WAITING)
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1031)
at java.lang.Thread.sleep(Thread.java:985)
at testapp.MainActivity.SleepAMinute(MainActivity.java:18)
at testapp.MainActivity.access$100(MainActivity.java:12)
at testapp.MainActivity$LockerThread.run(MainActivity.java:36)
從這個報告中,我們可以看到兩個執行緒的堆疊追蹤。第一個(「主」執行緒)卡在MainActivity.java:46
處,而第二個執行緒(名為「App: Locker」)在MainActivity.java:18
處鎖定在睡眠狀態。
從這裡開始,如果我們看這兩行,我們一定會明白死鎖的原因!
請注意,某些崩潰報告庫(例如 Crashlytics)會報告未捕獲異常時的所有執行緒堆疊追蹤。在這種情況下,讓所有執行緒處於同一個異常可能會很麻煩。在這種情況下,只需使用setReportMainThreadOnly()
即可。
設定不同的超時(預設為 5000 毫秒):
if ( BuildConfig . DEBUG == false ) {
new ANRWatchDog ( 10000 /*timeout*/ ). start ();
}
預設情況下,如果偵錯器已連接或應用程式正在等待偵錯器連接,則看門狗將忽略 ANR。這是因為它將執行暫停和斷點檢測為 ANR。若要停用此功能並拋出ANRError
,即使偵錯器已連接,您可以新增setIgnoreDebugger(true)
:
new ANRWatchDog (). setIgnoreDebugger ( true ). start ();
如果您不想在偵測到 ANR 時使應用程式崩潰,則可以啟用回調:
new ANRWatchDog (). setANRListener ( new ANRWatchDog . ANRListener () {
@ Override
public void onAppNotResponding ( ANRError error ) {
// Handle the error. For example, log it to HockeyApp:
ExceptionHandler . saveException ( error , new CrashManager ());
}
}). start ();
在生產環境中交付應用程式時,這一點非常重要。當最終用戶手中時,最好不要在 5 秒後崩潰,而是簡單地將 ANR 報告給您使用的任何報告系統。也許再過幾秒鐘,應用程式就會「解凍」。
如果您希望在 ANRError 中只報告您自己的線程,而不是所有線程(包括FinalizerDaemon
線程等系統線程),您可以設定前綴:僅報告名稱以前綴開頭的線程。
new ANRWatchDog (). setReportThreadNamePrefix ( "APP:" ). start ();
然後,當您啟動線程時,不要忘記將其名稱設定為以前綴開頭的內容(如果您希望報告它):
public class MyAmazingThread extends Thread {
@ Override
public void run () {
setName ( "APP: Amazing!" );
/* ... do amazing things ... */
}
}
如果您只想獲得主線程堆疊追蹤而不是所有其他線程,您可以:
new ANRWatchDog (). setReportMainThreadOnly (). start ();
有時,您會想知道應用程式已凍結一段時間,但又不想報告 ANR 錯誤。您可以定義一個在報告錯誤之前將被呼叫的攔截器。攔截器的作用是定義在給定的凍結持續時間內是否應引發或延遲 ANR 錯誤。
new ANRWatchDog ( 2000 ). setANRInterceptor ( new ANRWatchDog . ANRInterceptor () {
@ Override
public long intercept ( long duration ) {
long ret = 5000 - duration ;
if ( ret > 0 ) {
Log . w ( TAG , "Intercepted ANR that is too short (" + duration + " ms), postponing for " + ret + " ms." );
}
return ret ;
}
})
在此範例中,ANRWatchDog 以 2000 毫秒的逾時啟動,但攔截器將推遲錯誤,直到達到至少 5000 毫秒的凍結時間。
ANRWatchDog 是一個線程,因此您可以隨時中斷它。
如果您正在使用 Android 的多進程功能進行程式設計(例如在新進程中啟動活動),請記住每個進程都需要一個 ANRWatchDog 執行緒。
ANR-Watchdog 可以免費用於非營利和商業用途,而且永遠如此。
如果您想對我的工作表示支持或讚賞,您可以隨意捐款!
(當然)我們將非常感激,但這絕不是獲得幫助或支持所必需的,我很樂意免費提供:)