Простой сторожевой таймер, который обнаруживает Android ANR (приложение не отвечает).
В настоящее время приложение Android не может обнаруживать и сообщать об ошибках ANR.
Если вашего приложения нет в магазине Play Store (либо потому, что вы все еще разрабатываете его, либо потому, что вы распространяете его по-другому), единственный способ исследовать ANR — это извлечь файл /data/anr/traces.txt.
Кроме того, мы обнаружили, что использование Play Store не так эффективно, как возможность выбрать собственную службу отслеживания ошибок.
В системе отслеживания ошибок Android есть запись о проблеме, описывающая этот недостаток, не стесняйтесь отмечать ее;)
Он устанавливает «сторожевой» таймер, который определяет, когда поток пользовательского интерфейса перестает отвечать на запросы. Когда это происходит, возникает ошибка со всеми трассировками стека потоков (сначала основной).
Да! Я рад, что вы спросили: именно поэтому он был разработан в первую очередь!
Поскольку это вызывает ошибку, обработчик сбоев может перехватить ее и обработать так, как ему нужно.
Среди известных работающих репортеров о авариях:
setReportMainThreadOnly()
)И нет причин, по которым он не должен работать с [вставьте сюда свою любимую систему отчетов о сбоях] .
Сторожевой таймер — это простой поток, который в цикле выполняет следующие действия:
В файле app/build.gradle
добавьте:
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
В классе вашего приложения в onCreate
добавьте:
new ANRWatchDog (). start ();
Загрузите последнюю версию 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 можно использовать бесплатно как в некоммерческих, так и в коммерческих целях, и так будет всегда.
Если вы хотите выразить поддержку или признательность моей работе, вы можете сделать пожертвование !
Это было бы (конечно) очень признательно, но ни в коем случае не обязательно для получения помощи или поддержки, которую я буду рад предоставить бесплатно :)