Life Cycle of an Activity
java -> android -> activity life cycle ...
So far we programmed "old-style": we created a single class that extended Activity, implemented the onCreate method, added a few widgets and event handlers and called the whole thing a program or application. The reality of programming for Android, however, is more complex:
- An application is a collection of tasks, each of which is handled by a separate, small, well-defined activity. Thus, a single application consists of a collection of interconnected activities. For example a game could consist of six activities: a splash screen, a main menu screen, a set-options screen, a game-play screen, and a save-game screen, and a load-game screen. Each "screen" is controlled by its own activity.
- An activity could be used by the application of which it is a part or it could offer services to other activities belonging to other applications. For example a game could include an activity to select a music track to play in the background. That same activity could be used by a slideshow application to pick its background music.
- Your application could use activities of other applications. For example, you write a program that needs to place a phone call. It should use the "dial out" activity for that.
- Any of the activities of your application could be interrupted at any time. The battery could be low, no more memory is available - after all we are programming for small devices with limited resources - or, very likely, an incoming phone call can interrupt our application any time (we are programming for smart phone).
- An application might need to continue in the background, or even run entirely without a user interface. A music player, for example, might continue playing even if the phone's screen is turned off, or a program might monitor a resource for changes all the time (such as an email program constantly checking for new mail).
Let's deal with the basic building block of an application or program: the Activity class. An activity has essentially four states:
- If an activity in the foreground of the screen, it is active or running.
- If an activity has lost focus but is still visible, it is paused. A paused activity is completely alive (it maintains all state and member information and remains attached to the window manager), but can be killed by the system in extreme low memory situations.
- If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.
- If an activity is paused or stopped, the system can drop the activity from memory by either asking it to finish, or simply killing its process. When it is displayed again to the user, it must be completely restarted and restored to its previous state.
Here are the four states in a diagram including the transition paths from one state to another (the image is taken from the Android SDK documentation).
Thus, an activity usually overrides the following methods to transition correctly between states:
- onCreate: Called when the activity is first created. This is where you should do all of your normal static set up: create views, attach listeners, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one. Always followed by onStart().
- onRestart: Called after your activity has been stopped, prior to it being started again. Always followed by onStart()
- onStart: Called when the activity is becoming visible to the user. Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden.
- onResume: Called when the activity will start interacting with the user. At this point your activity is at the top of the activity stack, with user input going to it. Always followed by onPause().
- onPause: Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns. Followed by either onResume() if the activity returns back to the front, or onStop() if it becomes invisible to the user.
- onStop: Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed. Followed by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away.
- onDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
Each of these methods should place a call to its superclass method. Thus, a complete framework for an activity should look like this (create a new project called FirstLife). We've added log calls to each method so we can see when it is called - those log calls would not be necessary in a real activity):
public class FirstLife extends Activity { private final static String DEBUG_TAG = "FirstLifeLog"; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(DEBUG_TAG, "onCreate executes ..."); setContentView(R.layout.main); } protected void onRestart() { super.onRestart(); Log.i(DEBUG_TAG, "onRestart executes ..."); } protected void onStart() { super.onStart(); Log.i(DEBUG_TAG, "onStart executes ..."); } protected void onResume() { super.onResume(); Log.i(DEBUG_TAG, "onResume executes ..."); } protected void onPause() { super.onPause(); Log.i(DEBUG_TAG, "onPause executes ..."); } protected void onStop() { super.onStop(); Log.i(DEBUG_TAG, "onStop executes ..."); } protected void onDestroy() { super.onDestroy(); Log.i(DEBUG_TAG, "onDestroy executes ..."); } }
Now start the activity in debug mode and watch the LogCat output:
When the activity first starts:
From activity start to pressing the device BACK button:
From activity start to pressing the device HOME button:
From activity start to pressing the device HOME button to long-click on HOME to bring activity back:
From activity start to interrupting it by pressing PHONE to returning by pressing BACK:
Now add a single EditText field to layout.xml to see what happens to user input as an activity goes through its cycles. It is best to install the activity on a real devices to see the impact of a screen orientation change.
- Start activity, type "Hello" into text field. Press HOME to go to the home screen, then long-click HOME and bring the activity back to the foreground: the text is still there
- Start activity and type "Hello" into the text field. Press BACK then restart the activity from the home screen: the text is gone
- Start activity and type "Hello". Rotate device to get the screen orientation to change. If you ran the activity in debug mode on a real device (make sure to set debug mode to true in the manifest file first) you'd see the same calls as pressing BACK and restarting the app, i.e. onDestroy is called: the text is still there, however
Next we will learn how to tie together multiple activities into one application, maintaining state data like user input when appropriate as activities call each other.