11

I have an Android activity that calls finish() inside it's onStop() so when I switch to other activities (including the main menu), the activity will be shut down. Up this point, everything works as expected.

However, when I run the application again, (sometimes, not always) I notice the application runs using the same PID as the previous and it calls onCreate() again. I didn't see any call to onRestart() so I assume that onCreate() call is performed straight after onStop(), which is something that violates the activity lifecyce. When the app uses a new PID, I can understand why onCreate() is called, that's because this is the beginning of the activity.

Anyone knows why this happen?

A bit about the app I am developing: This is a Unity + Vuforia + Android application. I create a custom activity because I need to create a native UI on Android (instead of from Unity).

I found a similar issue reported into the Android project: http://code.google.com/p/android/issues/detail?id=15331 but I am not sure if the cause is the same or not.

update: From what I see from the log, after the finish() call, there is no call to onDestroy(). However, if the problem I mentioned happens (the activity is started using the same process), there is a call to onDestroy() at the beginning of activity.

update: Sorry for the late update. Here I show an excerpt of the logcat.

## First run

I/ActivityManager(  265): Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=the.app/the.app.UnityAriusActivity bnds=[238,115][351,273] } from pid 423
I/ActivityManager(  265): Start proc the.app for activity the.app/the.app.UnityAriusActivity: pid=1686 uid=10013 gids={3003, 1006, 1015}
D/arius   ( 1686): UnityAriusActivity: onStart
D/arius   ( 1686): UnityAriusActivity: onResume

## Home button is pressed

I/ActivityManager(  265): Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10200000 cmp=com.sonyericsson.home/.HomeActivity } from pid 265
D/arius   ( 1686): UnityAriusActivity: onPause
D/arius   ( 1686): UnityAriusActivity: onStop

## Second run

I/ActivityManager(  265): Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=the.app/the.app.UnityAriusActivity bnds=[238,115][351,273] } from pid 423

## Same process, onStart is called again

D/arius   ( 1686): UnityAriusActivity: onStart
D/arius   ( 1686): UnityAriusActivity: onResume
I/ActivityManager(  265): Displayed the.app/the.app.UnityAriusActivity: +500ms
D/Unity   ( 1686): Creating OpenGL ES 2.0 context (RGB16 565 16/0)
W/IInputConnectionWrapper(  423): showStatusIcon on inactive InputConnection
I/QCAR    ( 1686): onSurfaceCreated

## Strangely, there's an onDestroy here

D/arius   ( 1686): UnityAriusActivity: onDestroy

## Unity apparently kills the process from its onDestroy

I/Process ( 1686): Sending signal. PID: 1686 SIG: 9
I/ActivityManager(  265): Process the.app (pid 1686) has died.

The problem is that, there's an onDestroy() after onStart() on the second run. My activity is basically a subclass of Vuforia/QCAR activity which is also a subclass of activity from Unity. So, inside my onDestroy(), I make a call to the superclass' (super.onDestroy()) and also the same for the other methods that I override.

If I looked at the Unity and Vuforia/QCAR Android library (I was curious so I decompiled them -- yeah this may be not right), inside Unity's onDestroy(), Unity tries to kill its own process (which is the application process).

Process.killProcess(Process.myPid());

So, when this happens, my app just shut down again. If the second run uses different process, that strange onDestroy() does not happen.

I have also tried the noHistory approach. But the same thing still happens :( When the second run uses the same process, a late onDestroy() will appear and then the process is kill by Unity.

fajran
  • 2,769
  • 22
  • 13
  • I also need to call `finish()` when the user presses the home button. That's why I'm calling it from `onStop()`. – fajran Jun 19 '12 at 10:41
  • Any call to finish() will force onCreate to run again, since this will destroy the Activity – Mohamed_AbdAllah Jun 21 '12 at 15:16
  • 1
    What exactly is the problem here? That onDestroy() is not being called? Or that it is being called? The Activity Lifecycle seems to require that you handle both possibilities. – Chris Stratton Jun 21 '12 at 22:29
  • Just a guess for the solution : keep all as it is, in Manifest file set that activity attribute `android:launchMode="singleInstance"` or try with `singleTask` – MKJParekh Jun 22 '12 at 05:22
  • If the application process is killed it should receive a new PID, so this clearly sounds like the bug. Have you tried to detect it with static field initialized in onCreate? – giZm0 Jun 27 '12 at 18:13
  • It looks like your trying to follow a state machine like logic without proper handling of processes... – Serguei Fedorov Jun 27 '12 at 21:32

4 Answers4

12

You are making an understandable, but critical error in assuming that a new activity must run in a new process. That is not actually the case on android - you can have the onCreate() of a new activity instance occur in a process that has been kept around after hosting an earlier activity instance.

This can make anything that is static with respect to a process (especially, though not exclusively in native code) puzzlingly unreliable.

Because the activity that is being started is a new one, it will not receive an onRestart() - that would happen only if you were restarting an existing activity.

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117
  • So you say it's possible for a completely new activity (in regards to its lifecycle) to reuse previous process? – fajran Jun 21 '12 at 20:23
  • I just updated my question. When the activity is started again using the same process, I see a call to `onDestroy()` which is supposedly done after the `finish()` call. This is actually what I don't want to happen. – fajran Jun 21 '12 at 20:35
  • 2
    There is no guarantee that onDestroy() will happen, especially if the process is being disposed of - look at the killable column in the Activity Lifecycle diagram. – Chris Stratton Jun 21 '12 at 22:28
  • Well.. if the activity finishes, it's fine if `onDestroy()` is not called. But not if it happens when the activity is started. – fajran Jun 28 '12 at 09:06
  • you could be seeing a configuration change cycle – Chris Stratton Jun 28 '12 at 09:14
  • This is what I have regarding the config change `android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|fontScale"` Unity uses them so I just use them as well. – fajran Jun 28 '12 at 09:35
  • Does that mean it's possible that `onCreate()` gets called even if `onDestroy()` hasn't been called (for the same activity)? –  Jul 03 '21 at 22:44
5

Why don't you just set noHistory="true" on the activity's manifest entry? Then you don't have to worry about manually finishing the activity in onStop().

Search for noHistory in http://developer.android.com/guide/topics/manifest/activity-element.html

Or, alternatively, set the FLAG_ACTIVITY_NO_HISTORY in your startActivity() intent. http://developer.android.com/reference/android/content/Intent.html#FLAG%5FACTIVITY%5FNO%5FHISTORY

Nikhil
  • 16,194
  • 20
  • 64
  • 81
Josh
  • 10,618
  • 2
  • 32
  • 36
  • @fajran - I should have mentioned above that the way you're calling `finish()` in `onStop()` seems like a hack. Is there a good reason you aren't using a more platform-friendly way of preventing your activity from entering into the history stack? – Josh Jun 27 '12 at 13:34
  • I guess I do that because I didn't know about the noHistory option, I am relatively new in Android development :) Anyway.. I tried this and unfortunately I still see the problem :( – fajran Jun 28 '12 at 09:00
  • OK, back up a bit. You said you tried this. Which method did you try? I hope that you removed the `finish()` call from `onStop()` when you did this test, right? So what are the exact things that happen when you have `noHistory` set to `true`? Could you describe it like "Open Activity A. Open Activity B from A. Press Home. Open app from homescreen. Still see Activity B!" – Josh Jun 28 '12 at 13:42
  • Let me reemphasize that chasing the lifecycle and trying to bend the OS process handling to your will is going to end in a lot of frustration. There are better ways to ensure you don't return to the same activity you were just viewing when you leave an app. – Josh Jun 28 '12 at 13:44
3

In the documentation in your link, the description of onDestroy is :

The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.

While for onStop is:

Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed. Followed by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away.

This means that finish() calls onDestroy not onStop, so when the activity is restarted, onCreate must be called, since your call to finish() inside onStop will force onDestroy to run.

Mohamed_AbdAllah
  • 5,311
  • 3
  • 28
  • 47
  • Yes I understand this part. I want to end the activity when it's inactive (i.e. `onStop()`). That's why I call `finish()` inside `onStop()`. – fajran Jun 21 '12 at 20:18
0

I'm running into a similar behavior: onDestroy strangely called after onCreate/onStart/onResume, when the activity is started. I don't have a definite confirmation, but my feeling is that the onDestroy call corresponds to the previous activity, not the new one. But for some reason, its execution is delayed until the process is reactivated again (when starting a new activity).

I believe this is due to calling "finish()" from onStop. I've noticed in my logs that the activity manager complains that activity reported to stop, but is not stopped anymore (it's actually finishing). So I'm wondering whether this messes up with the state the activity manager things my activity is in.

In your case, the end result is that the entire process is killed, due to the onDestroy call. As your new activity is started in the same process as the previous one, your app exits immediately.