2

If my app crashes (reason is unimportant - could be hardware issue, out of memory, whatever), Android always starts my app on the last activity. The app is used by people visiting an office for appointments. When the customer arrives, reception unlocks the app using a code for that client and then the client proceeds through several activities. So, there's client context that is needed for all activities in the app except the initial unlock screen. As a result, the app needs to return to the start screen if the app crashes for any reason, but Android always returns to the last activity.

It seems like this should be really easy to do, but Android "helpfully" restarts the last activity used, which can't proceed without the client context. Rather than write a bunch of code to detect if the app has restarted after a crash, I'd rather it just returned to the main activity each time. I've looked at the clearTaskOnLaunch and launchMode manifest options, but they don't seem to work after crashes. I have an UncaughtExceptionHandler on every thread, but certain crashes (e.g. in native code) just terminate the app without invoking it.

Yeah, I could bundle the client state up and restore it after a crash, but I don't want to serialize potentially sensitive information, and this seems like something the OS would just support since it sounds so basic.

Ok, now waiting for someone to tell me some incredibly obvious solution that I've missed...

Thanks.

Greg Taylor
  • 113
  • 6

1 Answers1

2

The obvious (LOL)
Put android:clearTaskOnLaunch="true" in your mainifest:

   <activity android:name=".StartActivity"
             android:clearTaskOnLaunch="true">
       <intent-filter>
           <action android:name="android.intent.action.MAIN"/>
           <category android:name="android.intent.category.LAUNCHER"/>
       </intent-filter>
   </activity>

savedInstanceState() is used when an Activity is forcefully terminated by the OS and other things i.e.:

  • when your Activity is in the background and another task needs resources
  • application crash
  • orientation change
  • NOT when user press's the "force close" button in settings

When this happens, onSaveInstanceState(Bundle outstate) will be called and it's up to your app to add any state data you want to save in outstate.
The data is held in memory only while the application is alive, in other words this data is lost when the application closes normally.

The not so obvious stuff (brute force approach [unsubtle])
After crash, check the savedInstanceState object on onCreate method of ALL activity's that might crash, and if it is not null (means it is restarted by android system) then finish the activity (maybe relaunch ?).

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (savedInstanceState != null) {
        finish();
    }
}

NOTE An activity also gets restarted in configuration changes (e.g. rotation), so if you use auto rotation you need to live with restart or code for it (not too hard).

Advanced stuff
Use UncaughtExceptionHandler() on every android java thread AND native ExceptionHandler() code if you use native (maybe with JNI callback to java).

Jon Goodwin
  • 9,053
  • 5
  • 35
  • 54
  • By "looked at" I meant I had indeed tried android:clearTaskOnLaunch="true". Doesn't work for crashes, it seems. :) – Greg Taylor Nov 09 '16 at 21:45
  • I've added some code, but I need to check it. Do you allow the app to change configuration when you rotate your device ? – Jon Goodwin Nov 09 '16 at 22:38
  • Ok, thanks. I think the TL;DR version is "there's no Android support for this and you gotta code it yourself." Seems like it should be a lot easier! Anyways, I'm going to mark this as the accepted answer. Thanks. – Greg Taylor Nov 10 '16 at 15:21
  • @GregTaylor Thanks Greg, yes it's harder than it looks, and should be ! – Jon Goodwin Nov 10 '16 at 15:29
  • One quick question, though. I wasn't able to ever get the Bundle passed in to onCreate to be non-null. I overrode onSaveInstanceState, and added some stuff to the Bundle, but never got it back no matter what I did. I'm assuming it's because I wasn't truly "crashing" the app. (I tried using System.exit, killing the app in the debugger, throwing an exception without a handler...) Are you able to simulate a crash? I can't get the app to crash at will. – Greg Taylor Nov 10 '16 at 15:33
  • @GregTaylor Is your UncaughtExceptionHandler() in place making it harder to crash?. I'll take a look, one guess kill -9 from adb maybe ? throw new RuntimeException("This is a crash"); – Jon Goodwin Nov 10 '16 at 15:40
  • @GregTaylor I thought a device rotation should produce a non-null Bundle, unless you disabled it . – Jon Goodwin Nov 10 '16 at 15:54
  • @GregTaylor see http://stackoverflow.com/questions/17829606/android-adb-stop-application-command-like-force-stop-for-non-rooted-device also http://android.stackexchange.com/questions/111835/detect-when-an-app-crashes-with-tasker-and-force-close-it-and-finally-launch-it – Jon Goodwin Nov 10 '16 at 16:22
  • 1
    Ah, did some more experimentation and this explains a lot: The crash behaviour is different when running in the debugger. When it restarts outside the debugger it seems to respect the clearTaskOnLaunch setting. Also, uncaught exceptions bring up the "App X has stopped" dialog while the app process keeps running inside the debugger. Tricky to test... – Greg Taylor Nov 10 '16 at 16:52
  • @GregTaylor Yes the debugger catches exceptions and keeps the app "alive" so you can see where in the code it crashed, and look at the stack. This common to all debuggers, I thought you were testing standalone (because that's what I do mostly). – Jon Goodwin Nov 10 '16 at 19:31