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
FragmentManager
and 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
FragmentManager
and 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 thelayout
that includes the fragment definition. Before that method returns:- The hosted fragment’s constructor is called
- The fragment’s
onInflate
method is called. - The fragment’s
onAttach
method is called. - The fragment’s
onCreate
method is called. - The fragment’s
onCreateView
method is called.
At this point, the activity’s call to
setContentView()
returns, and the rest of itsonCreate
method runs. - The activity’s
onStart
method is called. As part of this method, it callssuper.onStart
. Before that method returns:- The fragment’s
onActivityCreated
method is called. - The fragment’s
onViewStateRestored
method is called. - The fragment’s
onStart
method is called.
At this point, the activity’s call to
super.onStart
returns, and the rest of the activity’sonStart
method executes. - The fragment’s
- The activity’s
onResume
method is called. - The fragment’s
onResume
method 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
super
methods are critical, and - several of the fragment’s lifecycle methods are triggered by the activity’s call to
super
methods. 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 theonCreate
calls.
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
onPause
method is called. This method callssuper.onPause
. Before this method returns:- The fragment’s
onPause
method is called.
At this point the
super.onPause
method returns and the remainder of the activity’s method runs. - The fragment’s
- The activity’s
onStop
method is called. This method callssuper.onStop
. Before this method returns:- The fragment’s
onStop
method is called.
At this point the
super.onStop
method returns and the remainder of the activity’s method runs. - The fragment’s
- The activity’s
onDestroy
method is called. This method callssuper.onDestroy
. Before this method returns:- The fragment’s
onDestroy
method is called. - The fragment’s
onDestroyView
method is called. - The fragment’s
onDetach
method is called.
At this point the
super.onDestroy
method 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
FragmentTransaction
is 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
FragmentTransaction
is 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
onSaveInstanceState
after the activity’sonPause
method returns. The activity calls itssuper.onSaveInstanceState
as part of its own method. While this is executing:- The fragments’
onSaveInstanceState
methods are called.
After the fragments have been handled, the
super
method returns and the activity’sonSaveInstanceState
method completes. - The fragments’
- The activity’s
onRestoreInstanceState
method is called in between itsonStart
andonResume
methods.
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.