0

I've had a long standing problem with my application and have been unable to solve it. My app is made up of multiple Activities that call each other with StartActivityForResult. They then wait for the response and act accordingly. This works fine under normal circumstances. I have the following set in the manifest:

android:alwaysRetainTaskState = "true"

When the Android OS decides to kill an activity in my app it seems to want to kill the root activity. I see a log entry like this:

no longer want com.ddhsoftware.android.handbase 

It appears to close the root activity at this point and the application and a service I have running.

Then when I go back to the app by launching it again (or selecting from the press-and-hold-home button) I get a force quit message. The logs read this:

02-24 17:29:04.376 E/AndroidRuntime(14318): FATAL EXCEPTION: main
02-24 17:29:04.376 E/AndroidRuntime(14318): java.lang.RuntimeException: Unable to start    activity ComponentInfo{com.ddhsoftware.android.handbase/com.ddhsoftware.android.handbase.ListViewScreen}: java.lang.NullPointerException
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.os.Handler.dispatchMessage(Handler.java:99)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.os.Looper.loop(Looper.java:130)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.ActivityThread.main(ActivityThread.java:3683)
02-24 17:29:04.376 E/AndroidRuntime(14318): at java.lang.reflect.Method.invokeNative(Native Method)
02-24 17:29:04.376 E/AndroidRuntime(14318): at java.lang.reflect.Method.invoke(Method.java:507)
02-24 17:29:04.376 E/AndroidRuntime(14318): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-24 17:29:04.376 E/AndroidRuntime(14318): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-24 17:29:04.376 E/AndroidRuntime(14318): at dalvik.system.NativeStart.main(Native Method)
02-24 17:29:04.376 E/AndroidRuntime(14318): Caused by: java.lang.NullPointerException
02-24 17:29:04.376 E/AndroidRuntime(14318): at java.util.Arrays$ArrayList. (Arrays.java:47)
02-24 17:29:04.376 E/AndroidRuntime(14318): at java.util.Arrays.asList(Arrays.java:169)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.widget.ArrayAdapter. (ArrayAdapter.java:125)
02-24 17:29:04.376 E/AndroidRuntime(14318): at com.ddhsoftware.android.handbase.ListViewScreen.setupViewSelector(ListViewScreen.java:821)
02-24 17:29:04.376 E/AndroidRuntime(14318): at com.ddhsoftware.android.handbase.ListViewScreen.onCreate(ListViewScreen.java:114)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
02-24 17:29:04.376 E/AndroidRuntime(14318): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
02-24 17:29:04.376 E/AndroidRuntime(14318): ... 11 more
02-24 17:29:04.386 W/ActivityManager( 96): Force finishing activity com.ddhsoftware.android.handbase/.ListViewScreen

The problem is that this is a sub-activity from the root one, and the last visible one. It's no longer valid as it generates the array adaptor from a database that is opened in the root activity and since that has just been restarted, there is no database open at this point. While I do save the databases and records in the OnSaveInstanceState so nothing is lost, I can't reopen the databases and restore the position because the databases use encryption and the keys are never stored or cached for security reasons. I just want to return to the root activity in this case.

I would like to know if there is a way to have my app relaunch completely when it's restarted after being killed, and not try to restore any activities. I know that there are launchmodes I can set to always return to the root if the user switches out and back, but it's not an option in this case. I just want the app to be completely killed when the root activity is killed!

Thanks in advance for any advice.

Dave Haupert
  • 1,036
  • 8
  • 7
  • I added some checks to the other non-root activities OnCreate method. If the root activity has not yet initialized, I have call the finish method and skip the rest of the initialization. Amazingly it seems to do the trick- even though the activity was called with a wait for result command, it seems to just close quietly and the root activity comes back to the top. So I think I have a solution here! – Dave Haupert Feb 25 '12 at 03:33

3 Answers3

1

If you have main activity A calling a sub activity B, with B referring to static A's variables onCreate, and android kills your process for memory reasons when you were in B:

-When the users opens your application, it will first call B's oncreate and will crash as A's variables are not there anymore (process has been killed).

I have dealt with this smoothly like this:
on B's oncreate, check whether A's static vars are null. If yes, it means you had a crash caused by memory (as described above). You should do as follows:

setResult(999); 
finish(); 
return;

Then, A will proceed with oncreate as normally and recreate the static variables. You can set on A's onActivityResult:

if (resultCode==999) A.comeFromCrash = true;

and then in the end of A's onCreate:

if (comeFromCrash) { launch B ; comeFromCrash=false;}

Then you can add extra vars to control whether B is launching in default, or following a crash

Renjith K N
  • 2,613
  • 2
  • 31
  • 53
mirandes
  • 957
  • 10
  • 10
0

Look here to provide your app a real data model and don't get dependent of activities to get your data in your apps :

Intent.putExtras size limit?

Community
  • 1
  • 1
Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • Thanks for your post. The database and it's format are the core of this application so I have to use the NDK and a native library to encrypt/decrypt/query/sort/etc on the data. So the reason each activity waits for results are for things like knowing when a user selected new parameters for filtering so that I can re-query the database for a new list of records to show. This is why I need dependency between activities. The problem is that since the core app is being closed/restarted, all of the connections to the database are wiped out, yet those deeper activities don't know it. – Dave Haupert Feb 25 '12 at 01:02
0

Perhaps set all activity's to "listen" to the "root" activity. The "root" activity could broadcast when its onStop method are called, and thus notify all other activity's that its time to die? Not sure if that would help you out, its not a pretty solution either way.

Carl-Emil Kjellstrand
  • 1,233
  • 1
  • 10
  • 17
  • Thanks for your reply. The problem is that the OnDestroy methods are not called when the app is killed off. So there is no way of knowing that you're about to be killed. Otherwise, I'd just close up shop at that point and all would be great! Thanks anyway.. – Dave Haupert Feb 25 '12 at 00:57