The Android OS is a dangerous place for an activity. The demand for resources on a battery-operated platform is managed quite ruthlessly by the system. Our activities can be dumped from memory when it's running low, without even a moment's notice, along with any data they contain.
It is therefore essential that we understand the activity lifecycle and where our activities are on the back stack.
Android supplies a series of callbacks that are executed at each stage of the activity lifecycle and can be overridden, enabling us to anticipate user actions and execute code when the state of an activity changes.
To prepare for this exercise, start up a new Android project in Eclipse.
We are going to record each lifecycle state with a persistent TextView whenever any of the activity's callbacks are executed:
In the
main.xml
file, define the default TextView withandroid:id
—we usedandroid:id="@+id/text_view"
.Open the main Java activity source file and declare a class-wide TextView to correspond with the one we just defined in XML:
private TextView mTextView;
Next, complete the
onCreate()
method as follows:@Override public void onCreate(Bundle state) { super.onCreate(state); setContentView(R.layout.main); mTextView = (TextView) findViewById(R.id.text_view); mTextView.append("\n created"); }
Now, override the
onPause()
callback like so:@Override public void onPause() { super.onPause(); mTextView.append("\n pausing"); }
Override the
onResume()
method in a similar fashion:@Override public void onResume() { super.onResume(); mTextView.append("\n resuming"); }
Repeat this for each of the remaining lifecycle callbacks,
onStart()
,onRestart()
,onStop()
, andonDestroy()
.Run the application and observe what happens when the activity is interrupted by pressing the Back and Home keys or when a call is sent to or from the phone.
Take a look at the next diagram. Our activity can exist in one of three states: active, paused, or stopped. There is also a fourth state, destroyed, but we can safely ignore it:
An activity is in the
active state when its interface is available to the user. It persists from onResume()
until onPause()
which is brought about when another activity is pushed onto the stack. If this new activity does not entirely obscure ours, then ours will remain in the paused state until the new activity is finished or dismissed. It will then immediately call onResume()
and continue.
When a newly started activity fills the screen or makes our activity otherwise invisible then our activity will enter the stopped state and resumption will always invoke a call to onRestart()
.
When an activity is in either the paused or stopped state, the operating system can (and will) remove it from memory when memory is low or when other applications demand it.
Note
In circumstances where resources are demanded suddenly, for example if the user receives a phone call, Android may kill our activity without even running the code in our onDestroy()
method. Where possible we should use onPause()
or onStop()
to enable the user to navigate back to our activity seamlessly.
It is worth noting that we never actually see the results of the onDestroy()
method, as by this point the activity has been removed. If you want to explore these methods further then it is well worth employing Activity.isFinishing()
to see if the activity is really
finishing before onDestroy()
is executed, as seen in the following snippet:
@Override public void onPause() { super.onPause(); mTextView.append("\n pausing"); if (isFinishing()){ mTextView.append(" ... finishing"); } }
Despite the effort that we have had to put into preventing Android from shutting down our components prematurely, there are times when we want to deliberately exit an activity. Despite Android's robust approach to resource management it will not wipe our application if there is no demand or if memory is readily available. Although an activity that persists in this way is unlikely to have much of a negative impact, the user will most likely not see it that way and blame our application for draining their battery.
To shut down an activity, directly call its finish()
method, which in turn calls onDestroy()
. To perform the same action from a child activity use the finishFromChild(Activity child)
where child
is the calling sub-activity.
It is often useful to know whether an activity is being shut down or merely paused, and the isFinishing(boolean)
method returns a value indicating which of these two states the activity is in.
In this chapter we have seen the fundamental role that the Activity class plays in an Android application. Now that we can control the general structure of our projects, it's time to look more closely at the individual components such as layouts and fragments, components that make up the detail of our applications.