There are numerous articles on the Internet that provide an overview of the Android Activity lifecycle, as well as the corresponding Fragment lifecycle. One thing that I have found lacking, however, is a detailed examination of the relationship between the two – in particular, exactly what events trigger what other events. Thus, I’ve set out to remedy that particular lack with this blog post. Code for this particular post may be found at https://github.com/SilverBayTech/FragmentLifeCycle.
Reviewing Android Lifecycle Events
As you’re probably aware at this point, an Activity can define the following lifecycle callbacks:
| Method | Description |
|---|---|
onCreate() |
Called when the activity is first created. This is where you normally do your view setup, etc. This method also provides you with a Bundle containing the activity’s previously frozen state, if there was one. |
onRestart() |
Called if your activity has been stopped and is now being restarted. |
onStart() |
The activity is becoming visible to the user. |
onResume() |
The activity will begin interacting with the user. It is now on the top of the activity stack, with any input from the user going to it. |
onPause() |
The activity is no longer on the top of the activity stack. Another activity may have started on top of it, or the user may have backed out of this activity. |
onStop() |
The activity is no longer visible to the user. Another activity may be completely obscuring this one, or it may be on its way to being destroyed. |
onDestroy() |
The activity is being destroyed, either because of a call to finish() or because the system needs the space. |
A Fragment has all of those methods, plus the following additional ones:
| Method | Description |
|---|---|
onInflate() |
This method is not traditionally mentioned as part of the lifecycle events, as not all fragments will go through it. For fragments defined in XML, however, this offers the fragment the opportunity to obtain any XML arguments that were part of its definition. |
onAttach() |
Called after the fragment has been associated with an activity. |
onCreateView() |
Called when it is time for the fragment to create its own view structure. |
onActivityCreated() |
Called once the fragment’s activity’s onCreate has been completed. As we’ll see, the activity’s onCreate is (indirectly) responsible for causing several of the fragment’s lifecycle events to be called, and the fragment’s onCreate method is called before the activity’s onCreate method has been completed. |
onViewStateRestored() |
Tells the fragment that all of the saved state in its view hierarchy has been restored. |
onDestroyView() |
Tells the fragment that its view is being destroyed so that it can clean up any associated resources. |
onDetach() |
Called just before the fragment is disassociated from its activity. This is the final call before the fragment object will be released to the garbage collector. |
Creating and Destroying Fragments
There are two ways that a Fragment can end up on the screen:
- The view defined by an activity can contain XML definitions for the fragment. This is done by embedding an XML
<fragment>element within the view definition. In this case, the fragment is automatically set up when the activity’s view is inflated. I’m going to refer to this kind of fragment as being “embedded.” - The activity can “manually” create the fragment and add it to the activity’s view using the
FragmentManagerand aFragmentTransaction. When doing this, you have the choice of having the transaction added to theFragmentManager‘s back stack or not.
Similarly, there are three ways that a Fragment can be removed from the screen:
- If it is part of the view for an activity and the activity’s view itself is taken off the screen, such as by the user going back to a previous activity.
- If, when the view was manually added to the activity, it was also added to the
FragmentManager‘s back stack, and then the back stack is popped, either programmatically, or via the user pressing the back button. - The app can manually remove or replace the fragment, again using the
FragmentManagerand aFragmentTransaction.
The code https://github.com/SilverBayTech/FragmentLifeCycle is for a simple application that allows one to explore all of these possibilities. The first activity displayed contains a “Start” button that loads a second activity. The latter is where all the “meat” is – it contains a fragment via the view’s XML, plus the ability to add an additional fragment either with or without involving the FragmentManager back stack. All the lifecycle event calls are logged so that we can see exactly what is called when.
Playing with the App
Launching an Activity with an Embedded Fragment
Pressing the “Start” button on the first activity loads the second activity, which contains the embedded fragment. If you check out LogCat, you’ll find that the sequence of events is as follows:
- The constructor for the new Activity is called.
- The activity’s
onCreate()lifecycle method is called. - The activity’s
onCreate()method callssetContentView()passing thelayoutthat includes the fragment definition. Before that method returns:- The hosted fragment’s constructor is called
- The fragment’s
onInflatemethod is called. - The fragment’s
onAttachmethod is called. - The fragment’s
onCreatemethod is called. - The fragment’s
onCreateViewmethod is called.
At this point, the activity’s call to
setContentView()returns, and the rest of itsonCreatemethod runs. - The activity’s
onStartmethod is called. As part of this method, it callssuper.onStart. Before that method returns:- The fragment’s
onActivityCreatedmethod is called. - The fragment’s
onViewStateRestoredmethod is called. - The fragment’s
onStartmethod is called.
At this point, the activity’s call to
super.onStartreturns, and the rest of the activity’sonStartmethod executes. - The fragment’s
- The activity’s
onResumemethod is called. - The fragment’s
onResumemethod is called. Note that unlike the previous lifecycle methods, this call is not nested within the activity’s method.
The significant takeaways here are that:
- The calls to the
supermethods are critical, and - several of the fragment’s lifecycle methods are triggered by the activity’s call to
supermethods. If the relationship between the activity’s lifecycle and the fragment’s lifecycle is complex (which is obviously not ideal), this may need to be taken into account – particularly the “nesting” of theonCreatecalls.
Destroying an Activity with an Embedded Fragment
The activity with the embedded fragment can be destroyed simply by pressing the “back” button to return to the initial activity. If you do this, you will see that the sequence of events is as follows:
- The activity’s
onPausemethod is called. This method callssuper.onPause. Before this method returns:- The fragment’s
onPausemethod is called.
At this point the
super.onPausemethod returns and the remainder of the activity’s method runs. - The fragment’s
- The activity’s
onStopmethod is called. This method callssuper.onStop. Before this method returns:- The fragment’s
onStopmethod is called.
At this point the
super.onStopmethod returns and the remainder of the activity’s method runs. - The fragment’s
- The activity’s
onDestroymethod is called. This method callssuper.onDestroy. Before this method returns:- The fragment’s
onDestroymethod is called. - The fragment’s
onDestroyViewmethod is called. - The fragment’s
onDetachmethod is called.
At this point the
super.onDestroymethod returns and the remainder of the activity’s method runs. - The fragment’s
Here again, you can see the criticality of the call to the super methods, as well as the way that the calls to the fragment “nest” inside the calls to the activity.
Adding a Fragment Manually
If you press the “Add Fragment” button on the second activity, this adds manually a fragment to the bottom third of the screen. Pressing “Push Fragment” does exactly the same thing, except for the fact that the fragment is added to the FragmentManager‘s back stack.
The sequence of events in this case are:
- The fragment’s constructor is called.
- The fragment is added to the activity via a
FragmentTransaction - The
FragmentTransactionis committed, and the method doing this work returns. - Asynchronously, the fragment’s lifecycle events are called in order:
- onAttach
- onCreate
- onCreateView
- onActivityCreated
- onStart
- onResume
Here you can see that there is no “interleaving” of the fragment’s lifecycle events with that of the activity’s, since the activity is not changing state. In addition, the call to onInflate is omitted, since the fragment is not being created as part of an XML view inflation. The fact that this method isn’t always called may be one of the reasons that it’s not traditionally listed as one of the fragment lifecycle methods.
If you then press the “Remove Fragment” button, the activity manually removes the fragment from its view. Here again:
- The fragment is removed from the activity via a
FragmentTransaction - The
FragmentTransactionis committed, and the method doing this work returns. - Asynchronously, the fragment’s lifecycle events are called in order:
- onPause
- onStop
- onDestroyView
- onDestroy
- onDetach
Had you instead destroyed the activity by pressing the “back” button, you would have found that the lifecycle events for the added fragment are called in exactly the same manner as those for the hosted fragment. In my particular case, the methods for the added fragment are called after those for the hosted fragment, but it would be extremely bad design (in my opinion) to rely on this behavior.
Adding a Fragment Manually and Using the Back Stack
If, instead of “Add Fragment,” you press “Push Fragment” the fragment is added to the back stack as part of the FragmentTransaction. The only change that you will see in this case is that the BackStackListener‘s onBackStackChanged method is called. This call comes all the way at the end of the sequence – after the new fragment’s onResume call is made when the fragment is being added, and after the fragment’s onDetach call is made when the fragment is being removed. This behavior is the same whether the back stack is popped manually or via the “back” button.
Activity Reconstruction on Rotation
As you’re probably aware, unless you take steps to prevent it, when your device is rotated the operating system will typically destroy your activity and recreate it. This allows you to more easily do things like have different layouts for portrait vs. landscape.
In this case, the sequence of events is the same as the “destroy” followed by the “create” sequences above, with the following exceptions:
- The operating system calls the activity’s
onSaveInstanceStateafter the activity’sonPausemethod returns. The activity calls itssuper.onSaveInstanceStateas part of its own method. While this is executing:- The fragments’
onSaveInstanceStatemethods are called.
After the fragments have been handled, the
supermethod returns and the activity’sonSaveInstanceStatemethod completes. - The fragments’
- The activity’s
onRestoreInstanceStatemethod is called in between itsonStartandonResumemethods.
Thus, again, the call to the super method within onSaveInstanceState is important.
Fragments do not have an onRestoreInstanceState method. They are, however, passed the Bundle with the restored state information as part of their onCreate call in this case. (This argument is null if the fragment is being created, as opposed to being restored.)
Summary
As you can see, the calls to the various lifecycle methods are interleaved in a number of situations. Thus, if fragment state depends on activity state, one must be careful to understand this interleaving in order to make sure that one doesn’t try to access information before it is set.
Update – 06-Oct-2014
An eagle-eyed reader (thanks, Haluk) pointed out that I had an extra, incorrect, call to onActivityCreated listed during the fragment removal section. That was a cut-and-paste error on my part, and has been corrected.
This post was written by Kevin Hunter and originally appeared on Silver Bay Technology’s blog.