3

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) and PendingIntent.

However the context still has apparent access to contextual resources (getString(), Resources and oddly enough Notifications).

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>
Community
  • 1
  • 1
ahodder
  • 11,353
  • 14
  • 71
  • 114
  • why have you got the `BoomMitActivity` as a `static`? – Ron May 11 '12 at 18:44
  • @userSeven7s You can't declare a nested activity as none static. I could have just as easily placed it in its own class, but for testing it was easier just to have it in AndroidTestoActivity. – ahodder May 11 '12 at 20:42
  • Is it the same with a normal class too..? – Ron May 12 '12 at 04:55
  • What do you mean? Applications, Services and Activities must be static in order to be registered to the manifest. – ahodder May 14 '12 at 14:33

1 Answers1

3

Nothing happens to Context itself. If you are talking about when you are in the situation where the app crash dialog is up, then the crashing thread is sitting there waiting for the user to press a button and let it proceed to kill itself. At this point the system knows your app is trashed, and is just waiting for the user to confirm and finally terminate it. So you really should assume you are on the way out and not rely on much of anything working.

Further, if this crash came from the main thread, then that thread is now sitting there blocked waiting for the user to confirm the crash dialog so it can commit suicide. It is not sitting there processing its message loop, it is sitting there completely blocked waiting for suicide. No work that would be scheduled on that thread will execute. For the main thread, this includes callbacks on components like Activity.onCreate(), Service.onStart(), and on and on. For any thread, this includes dispatching any work for window UIs associated with the thread. Again if this is the main thread, this probably means all of your UI.

hackbod
  • 90,665
  • 16
  • 140
  • 154
  • Ok, this makes a lot of sense, thanks. I was just hoping to have a more elegant crash than, "Opps, we're sorry that your developer is an idiot". – ahodder May 14 '12 at 21:04
  • What would you consider more elegant? – hackbod May 15 '12 at 19:19
  • Just disappearing with no warning or cause -- making me tap the icon 3 more times until I realize it just isn't going to work... that's how iPhone does it... I kid, I kid!!! :) – Dan May 15 '12 at 19:57