Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to exit (only) current activity if UncaughtExceptionHandler occurs?

Tags:

android

I did a bit of coding to test out Thread.UncaughtExceptionHandler for a specific use case (explained below).

Firstly, I have a BaseActivity implemented this way.

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                Log.e("CRASH_REPORT", "Activity crashed!");
                System.exit(0);
            }
        });
    }
}


By extending BaseActivity, any uncaught exception will end up being caught by the handler. System.exit(0) will terminate the VM belongs to the app.

Now, I created 2 activities with this hierarchy (both extending BaseActivity).

ParentActivity -> SubActivity


In ParentActivity, I have only 1 button that will start SubActivity on clicked (code omitted).

In SubActivity.onCreate(...), I purposely inject an exception to trigger uncaughtException(...).

public class SubActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        int crash = 1 / 0;
    }
}


When SubActivity executed, uncaughtException(...) triggered and the app stopped (obviously without the well known app stopped dialog).

What I want to know is whether its possible to just terminate the triggered Activity (SubActivity in this case) and app will roll-back (sort of) to its previous state (ParentActivity)?

Any advice is appreciated. Thank you.

like image 398
LightYearsBehind Avatar asked Nov 10 '22 04:11

LightYearsBehind


1 Answers

After some research, I believe there is NO WAY to return to previous Activity when uncaughtException(...) triggered as main thread has been stopped since.

Here, I will list down the ideas I have on "countermeasure" this issue.


1. Declare each Activity in different process (not recommended)

In the manifest file, add android:process=dedicated_process_name under each activity tag. Doing this will make each Activity running in its own process, thus ensuring crashing on 1 process does not affect another. This is not recommended, though.

<activity
    android:name=".ParentActivity"
    android:process="::parent_process" />


2. Force stop the app (System.exit(code)) and provide a callback where each Activity can define its own handling.

Create a BaseActivity with a onCrashed(...) callback.

public class BaseActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
                Log.e("CRASH_REPORT", "Activity crashed!");
                onCrashed(thread, throwable);
                System.exit(0);
            }
        });
    }

    protected void onCrashed(Thread thread, Throwable throwable) {
        // space for rent
    }
}

All Activity extending from BaseActivity can decide what they want to do on crash. An example is to schedule to start the application again.

public class SubActivity extends BaseActivity
    @Override
    protected void onCrashed(Thread thread, Throwable throwable) {
        Intent i = new Intent(this, ParentActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
        AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        am.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pi);
    }

Alternatively, we can choose to implement uncaughtException(...) at Application level and Application will decide what to do next. (eg. restart current Activity)

like image 53
LightYearsBehind Avatar answered Nov 14 '22 22:11

LightYearsBehind