У меня простая настройка:
-
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в этих условиях?