In conjunction a previous question
of mine, I would like to know exactly what happens to a context when an exception is caught by a Thread.UncaughtExceptionListener
. When the uncaught exception is received by the listener, the context seems to have fallen into a limbo state. It has access to some of its methods (primarily the ones pertaining to resources), but then a great many don't work (or don't visibly work). This includes (but isn't limited to, I'm sure there are more I haven't found):
Toast
(as in my link)Dialog
- Creation of new activities. This includes normal
Context.startActivity(Intent)
andPendingIntent
.
However the context still has apparent access to contextual resources (getString()
, Resources
and oddly enough Notification
s).
Why is this? What causes this state imbalance(?) in the context to prevent any context driven calls?
Below I have created a test application for you that is suppose to launch an error activity when an exception is left uncaught. To test the things I have mentioned (Toast and dialog) in the situation I have been doing, place their builders in the BoomMitActivity in lieu of the notification builder.
In the given example, the activity error out (how could it not?) and launches BoomMitActivtiy when the Notification
is clicked. However, BoomMit's onCreate
is never called.
Application:
public class AndroidTestoActivity extends Activity implements UncaughtExceptionHandler {
@Override public void onCreate(Bundle icicle) {
super.onCreate(icicle);
Thread.setDefaultUncaughtExceptionHandler(this);
throw new RuntimeException("HAHAHAHA, I broke you");
}
@Override public void uncaughtException(Thread arg0, Throwable arg1) {
finish();
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification note = new Notification(R.drawable.ic_launcher, "Boom!", System.currentTimeMillis());
Intent i = new Intent(this, BoomMitActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(this, 1, i, PendingIntent.FLAG_ONE_SHOT);
note.setLatestEventInfo(this, "Boom!", "Open BoomMitActivity", pi);
note.flags |= Notification.FLAG_AUTO_CANCEL;
nm.notify(1, note);
Log.d("TAG", "End");
}
static class BoomMitActivity extends Activity {
@Override public void onCreate(Bundle icicle) {
super.onCreate(icicle);
TextView tv = new TextView(this);
tv.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
tv.setBackgroundColor(0xffff0000);
tv.setText("BoomMitActivity is the one true activity");
tv.setTextColor(0xff00ffff);
setContentView(tv);
}
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name=".AndroidTestoActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="AndroidTestoActivity$BoomMitActivity"
android:label="I'm a real boy!"
android:taskAffinity=""
android:excludeFromRecents="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>