Recently I was investigating a crash in an Android app. I found the cause and fixed it but I've been wondering since then how I could have handled it ("handled" in the sense of trapping it to avoid an "unhandled" exception.)
The crash was occurring when I was starting up a new Activity. But it was not while executing any of the code visible to me in my source code. Instead it crashed after I exited the last event handler in my code, but before the View was displayed.
I had several event handlers in my Activity, such as onCreate()
, onPause() and onAttachedToWindow()
. In the latter I did a . . .
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
The program had originally been built against API 8 but when I switched to API 18 that's when it started blowing up. Based on another SO question I commented-out that line and the problem went away.
When it was crashing, the monitor showed . . .
W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x4136a960) E/AndroidRuntime: FATAL EXCEPTION: main java.lang.IllegalArgumentException: Window type can not be changed after the window is added. at android.os.Parcel.readException(Parcel.java:1429) at android.os.Parcel.readException(Parcel.java:1379) at android.view.IWindowSession$Stub$Proxy.relayout(IWindowSession.java:860) at android.view.ViewRootImpl.relayoutWindow(ViewRootImpl.java:4755) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1661) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1236) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5160) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791) at android.view.Choreographer.doCallbacks(Choreographer.java:591) at android.view.Choreographer.doFrame(Choreographer.java:561) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:176) at android.app.ActivityThread.main(ActivityThread.java:5365) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869) at dalvik.system.NativeStart.main(Native Method) I/Process: Sending signal. PID: 23536 SIG: 9 Disconnected from the target VM, address: 'localhost:8600', transport: 'socket'
My startActvity() was already wrapped in a try/catch, but it didn't land there . . .
Intent svc = new Intent(ctx, RegisterActivity.class);
svc.putExtra("Projectors2Register", params);
try {
ctx.startActivity(svc);
}
catch (Exception e) {
Log.e("ShowButtons(normal)Reg", "Exception" + e);
}
So where can I put a handler to catch these kinds of crashes in the future?
...N.B., By "these kinds" of crashes I don't mean specifically "TYPE_KEYGUARD"; I mean crashes that happen outside my code when the system is setting up or displaying a screen/view that was called earlier for inside my code.
In other words, I don't want the user to get "Unfortunately your app has stopped" errors without going through an error handler I write. I want to be able to log the details of every crash, what the user was doing, and to gracefully close connections and tell the user what happened.