I have a simple setup:
CrashHandler
- a class which implementsThread.UncaughtExceptionHandler
;CrashActivity
- an activity which can send user reports;MainActivity
- the main app with which the user should interact.
When there is an uncaught exception within the MainActivity
or any of it's threads, the CrashHandler
intercepts it and creates a notification with an intent to start the 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);
In the mean time Android shows an "Application crashed" message, the user clicks OK, the application is closed, then the user might click the notification
. If the notification
is clicked, the CrashActivity
starts and shows.
This code has been working for a long time in many different situations (crash on main thread, crash in a handler
, crash on a background thread
...). However, I recently discovered that it DOES NOT WORK if the exception is thrown in the OnClickListener.onClick
method in a listener attached to a button
in the MainActivity
. The situation is as follows:
- I execute code that deliberately throws a
NullPointerException
; CrashHandler
intercepts it and creates anotification
(which is shown);- Android DOES NOT show any messages (for example, there is no "Application crashed", which should be visible);
- The
MainActivity
is frozen; - IF the user clicks on the notification to launch the
CrashActivity
, a black screen is shown and everything freezes (the desired activity is not shown).
Logcat
shows that there is a timeout on launch, even before OnCreate
or any of my code:
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}
- If before clicking the
notification
I kill the app fromADB
, thenotification
works perfectly. If before clicking the
notification
I make some clicks and gestures on the frozen app, after a few seconds I receive a message about anANR
: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
If I click "yes, kill it", and then click the
notification
, it works perfectly.- If I add
System.exit
(-1) in theCrashHandler
just after creating the notification, the app immediately quits and the notification works perfectly (unfortunately, I can't go with this solution in production).
I have two questions:
- Why a
NullPointer exception
inOnClickListener.onClick
doesn't cause the app to crash, instead freezing it together with the OS and preventing other activities from starting? - What to do to avoid it in general, or at least, how to make the
CrashActivity
start in these conditions?