У меня простая настройка:
-
CrashHandler
- класс, который реализуетThread.UncaughtExceptionHandler
; -
CrashActivity
- действие, которое может отправлять отчеты пользователя; -
MainActivity
- основное приложение, с которым пользователь должен взаимодействовать.
Если в MainActivity
или любом из его потоков есть неперехваченное исключение, CrashHandler
перехватывает его и создает уведомление с намерением запустить CrashActivity
:
Intent it = new Intent("CrashReporter" + SystemClock.currentThreadTimeMillis());
it.setClass(context, CrashActivity.class);
it.setFlags(it.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
В то же время, когда Android показывает сообщение "сбой приложения", пользователь нажимает "ОК", приложение закрывается, а затем пользователь может нажать notification
. Если нажать notification
, начнется и показывается CrashActivity
.
Этот код долгое время работал во многих ситуациях (авария в главном потоке, авария в handler
, авария на фоне thread
...). Однако недавно я обнаружил, что он НЕ РАБОТАЕТ, если исключение выбрано в методе OnClickListener.onClick
в прослушивателе, прикрепленном к button
в MainActivity
. Ситуация такова:
- Я выполняю код, который намеренно бросает
NullPointerException
; -
CrashHandler
перехватывает его и создаетnotification
(который показан); - Android НЕ показывает никаких сообщений (например, нет "Application crashed", который должен быть видимым);
-
MainActivity
заморожен; - Если пользователь нажимает на уведомление для запуска
CrashActivity
, отображается черный экран и все зависает (желаемая активность не отображается).
Logcat
показывает, что при запуске есть таймаут, даже до OnCreate
или любого из моего кода:
I/ActivityManager(11826): START u0 {act=CrashHandler1196 flg=0x14000000 cmp=mycompany.myapp/.CrashActivity bnds=[0,102][720,230] (has extras)} from pid -1
W/KeyguardViewMediator(11826): verifyUnlock called when not externally disabled
W/ActivityManager(11826): Activity pause timeout for ActivityRecord{41f4d988 u0 mycompany.myapp/.MainActivity}
W/ActivityManager(11826): Launch timeout has expired, giving up wake lock!
W/ActivityManager(11826): Activity idle timeout for ActivityRecord{4225eeb8 u0 mycompany.myapp/.CrashActivity}
- Если перед нажатием
notification
я убью приложение изADB
,notification
отлично работает. -
Если перед нажатием
notification
я сделаю несколько кликов и жестов в замороженном приложении, через несколько секунд я получаю сообщение оANR
:E/ActivityManager(11826): ANR in mycompany.myapp (mycompany.myapp/.MainActivity) E/ActivityManager(11826): Reason: keyDispatchingTimedOut E/ActivityManager(11826): Load: 0.63 / 0.57 / 0.49
-
Если я нажму "да, убей его", а затем нажмите
notification
, он отлично работает. - Если я добавлю
System.exit
(- 1) вCrashHandler
сразу после создания уведомления, приложение немедленно прекратит работу, и уведомление будет работать отлично (к сожалению, я не могу пойти с этим решением в процессе производства).
У меня есть два вопроса:
- Почему
NullPointer exception
вOnClickListener.onClick
не приводит к сбою приложения, вместо этого замораживает его вместе с ОС и предотвращает запуск других действий? - Что делать, чтобы избежать вообще или, по крайней мере, как начать
CrashActivity
в этих условиях?