android-activityandroid-lifecyclestart-activityactivity-finish

Confused about activity lifecycle


I am a bit confused about some aspects of the activity lifecycle.

Say you have two activities A and B, and A is the launch activity. You start the app, and A goes through onCreate(), onStart() etc. Before onCreate() the activity class object is instantiated so you then create anything subsidiary you need in onCreate().

Then you use startActivity() to fire up activity B. A goes through onPause() etc, and B goes through the start up process as A did.

Now say you want to get back to A. Two ways - finish() (or onBackPressed() / back button that seems to do the same), or use startActivity() to fire up A. A should be on the history stack unless created with 'noHistory'.

With finish() or back, A now runs through onRestart(), onStart() etc - not onCreate() - which seems to make sense. Ie unless it was killed due to memory limits in the meanwhile it carries on from where it was. But, with startActivity() it always goes via onCreate(), onStart() etc instead. Which means everything set up in onCreate() the first time through is done again. Assuming it is on the history stack, why doesn't it go the onRestart() route?

Is it the case that whenever an activity is started via startActivity(), (1) the class object is actually always instantiated afresh and every else hanging off it must therefore be recreated in onCreate() or, (2) is the previous instantiation used (if it exists), and can one therefore detect that in onCreate() and effectively treat that pass through onCreate() as an onRestart()?


Solution

  • Assuming it is on the history stack, why doesn't it go the onResume() route?

    Because calling startActivity, by default, creates a new instance of the Activity. Each instance runs through the full lifecycle. So, in your example, it's not really A -> B -> A. It's more like A1 -> B -> A2, where A1 and A2 are instances of activity A.

    When you start the second instance of A it's just like creating B from the first instance of A. It's a brand new object and so has to be created from scratch.

    Is it the case that whenever an activity is started via startActivity(), (1) the class object is actually always instantiated afresh and every else hanging off it must therefore be recreated in onCreate() or, (2) is the previous instantiation used, and can one therefore detect that in onCreate() and effectively treat that pass through onCreate() as an onResume()?

    As mentioned above, it's usually (1). That is the default behavior. However, you can make the app navigate to the existing instance of A by using the proper launch mode flags. In which case the existing instance will be brought to the front of the stack, go through onStart and onResume (skipping onCreate since it already existed), but then also getting a call to onNewIntent to receive - well - the new intent that launched it again.

    In that case it is A -> B -> A because you're navigating to the original instance of A that already exists instead of creating a new one.


    EDIT

    Having looked further, does one get a similar result if A starts B with startActivityForResult()? Ie would the result come back to the original instance of A?

    "Similar" but not the same. The main difference being what happens to your navigation stack.

    If you do A -> startForResult -> B, then finish B and return your result, you're left with A.

    If you do A -> B -> startSingleTop -> A then you end up with B and A in the stack. So if you pressed back from A you'd end up back on B.

    Also, keep in mind that with Android you're pretty much never guaranteed to get back to "the original instance" of any activity. While A is in the background and you are on B, the system could kill that instance of A if it needs the memory. Whether you start A with single task or return to it after startForResult, you could be going back to a new instance.

    The reason I am looking at this is to make B like a dialog box for A. Ie, run A, go to B and adjust something, back to A and continue where left off

    For that scenario, startActivityForResult would be the best course of action. In general, avoid mucking with launch mode flags unless really necessary and you really know what you're doing - it gets complicated real fast.