Today as we continue the 31 Days of Android, we’ll talk about the Activity lifecycle.  Activities are the way in which users interact with your application.  Whenever you run an app, it’s an activity presenting something to you via the screen.  Activities function as the back end and controlling logic of everything you can do on screen.  Since activities are such an important part of an Android application, it’s very important that you understand the Activity lifecycle.  An application is typically built off of multiple such activities but it is possible that an app can run with only a single Activity

 

Different Activity States

While you might assume an Activity has two states, visible or not, there are more that you need to consider.  First an Activity can be in the creation state and not yet visible.  Secondly, it could be visible and currently interacted with by the user.  Next, the activity could be paused, which means that it is partially visible but without focus.  When the activity is fully obscured, such as when another activity launches or when the user taps home, it is stopped.  Lastly, it can be in a shut down phase when it’s being removed from the stack.  Speaking of stack, it’s useful to think of activities like a deck of cards (as mentioned in day 5).  At the bottom of that deck is the home screen which can never be taken off the stack.  When you start your application, the first activity is put on top of the home screen.  Whenever you call finish() in an activity it is taken off the stack.  Whenever you start a new activity, it’s placed on the top of the stack.  So if you had started 5 activities, the user could hit the back button to go down the stack of cards.

The State Diagram

When discussing the different states of an Android app, it’s useful to look at this diagram put together by Google:

Each of the ovals (Activity starts, Activity is running, Activity is shut down, Process is killed) represent important states that an activity can be in.  More important, each of the rectangular boxes (onCreate, onStart, onResume, onPause, onStop, onRecreate, onDestroy) represent methods that are called on your application during the state flow.  So far in this series, all of the logic we’ve done for altering the layout or adding click listeners has been in the onCreate method.  Looking at these may be a little confusing so we’ll try to break it down:

onCreate-called once on activity creation.

     onStart-called whenever the activity is started (partially visible to the user) and anytime the activity is brought back into view after a call to onStop.  Can be called multiple times.

          onResume-called when the activity is in the forefront on top of all others.  Can be called multiple times.

          onPause-called when the activity leaves the foreground but is still visible, or when the device goes to sleep.  Can be called multiple times.

     onStop-called whenever the activity is hidden from view.  Can be called multiple times.

onDestroy-the activity should release all of it’s resources and stop any background proccessing.  Only called once.

Hopefully this explains why most of the logic added and layout alteration is done in onCreate.  That is called once and the activity is kept in memory so you shouldn’t need to specify click listeners or perform other onCreate common functionality elsewhere.  In comparison, onStart and onResume may be called multiple times.  Furthermore, onResume will be called the first time your activity becomes visible, even though that may not make sense considering the name. 

It’s important to know that after any of an activity’s onPause, onStop, or onDestroy methods are called it is possible for the Dalvik Virtual Machine that runs all of the Android apps to kill your app without calling into any of the other methods in the status flow.  While it’s therefore important to persist any necessary data in the onPause method, be warned that starting the next activity will wait until the call to onPause is returned. 

Another thing that may not make sense initially is that when the device is rotated, the Activity is killed and recreated.  This is really hard for some new Android devs to grasp so I’ll say it again.  When the device is rotated, the Activity is killed and recreated.  If you think about the fact that different layouts can be used for different orientation this starts to make more sense.  The important take away is that you need to make sure you test that changing orientation doesn’t screw up the state of your Activity.

Saving and Restoring Activity State

Whenever an Activity is paused or stopped, it’s state is retained.  This is done automatically and something you don’t have to worry about.  However, when an Activity is destroyed, things can be a little different.  Before onStop is called (and possible before onPause) the Activitiy’s onSaveInstanceState method will be called.  This method takes in a Bundle which you can add data to.  This Bundle is then sent in to the onCreate method.  If, in the onCreate method, the Bundle isn’t null then you know that the Activity is being recreated.  Android’s default implementation of onSaveInstanceState already handles a lot of the persistence you might need.  By default, it will call onSaveInstanceState on all of the views inside of it.  So, for example if you’ve typed something into an EditText and then rotate the device, that text will appear after rotation as well.  onSaveInstanceState saves the text value and then it gets restored in onCreate.  It’s important to note that in order for this to work your Views must have a unique ID.

If your Activity has member variables that you need to save when the Activity is destroyed, then you would need to handle saving the state of these variables.  This is one example of something that you could handle in onSaveInstanceState.  Let’s say your Activity has a member variable named “Name” and you want to keep it’s value on recreation.  You could add it to the Bundle like so:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putString("MyString", this.Name);
}

Then in your onCreate method, you can check and see if you have a savedInstanceState and set your variable if you do:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    if (savedInstanceState != null) {
        this.Name = savedInstanceState.getString("MyString");
    }
    ...

One final note about onSaveInstanceState is that it won’t be called if the Activity is killed as a result of calling finish() or the user hitting the back button.  Since these are deliberate causes for the Activity to be ended, there isn’t a reason to save the state.  If you need to store any information when this happens, you’ll have to do it manually.

 

Configuration changes

The reason that your Activity is recreated when the orientation changes is that it is a change in the Resources.Configuration class.  Any changes to this class will trigger a recreation.  Other examples of things that change the Resources.Configuration class are sliding in or out a hardware keyboard (changing the input device), changing mode (i.e. night mode, car mode, etc), and more.  The rotation and keyboard are likely to be the most common configuration changes you’ll need to handle.  It is possible to override these changes, per Activity, so that you aren’t restarted.  This is done by adding a configChanges to your Activity in the manifest file.  For example, if you wanted to prevent restart on rotation for an Activity named ActivityTwo, you’d do the following:

<activity android:name=".ActivityTwo" 
    android:configChanges="orientation"
    android:label="@string/app_name"/>

Then in your Activity you would override the onConfigurationChanged method and just make it specify the orientation you want to maintain:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}

So here you’re saying to keep a portrait orientation even when the orientation may have been changed to landscape.

You should now have a good understanding of the Activity lifecycle now and when which event method are called.  One thing we didn’t cover is how to persist data long term so that you could load an Activity after your application has been restarted and restore it’s state to the last time it was used.  We’ll talk more about how to do this sort of longer term persistence later in the series.


Chris Risner