Chapter 18

Handling Activity Lifecycle Events

As you know, Android devices, by and large, are phones. As such, some activities are more important than others—taking a call is probably more important to users than playing Sudoku. And, since it is a phone, it probably has less RAM than your current desktop or notebook.

As a result of the phone’s limited RAM, your activity may find itself being killed off because other activities are going on and the system needs your activity’s memory. Think of it as the Android equivalent of the circle of life—your activity dies so others may live, and so on. You cannot assume that your activity will run until you think it is complete, or even until the user thinks it is complete. This is one example, perhaps the most important, of how an activity’s life cycle will affect your own application logic.

This chapter covers the various states and callbacks that make up an activity’s life cycle, and how you can hook into them appropriately.

Schrödinger’s Activity

An activity, generally speaking, is in one of four states at any point in time:

  • Active: The activity was started by the user, is running, and is in the foreground. This is what you are used to thinking of in terms of your activity’s operation.
  • Paused: The activity was started by the user, is running, and is visible, but a notification or something is overlaying part of the screen. During this time, the user can see your activity but may not be able to interact with it. Examples include the user being prompted to accept an incoming call, or being warned of a battery low or critically low state.
  • Stopped: The activity was started by the user, is running, but is hidden by other activities that have been launched or switched to. Your application will not be able to present anything meaningful to the user directly, but may communicate by way of a Notification.
  • Dead: Either the activity was never started (e.g., just after a phone reset) or the activity was terminated, perhaps due to lack of available memory.

Life, Death, and Your Activity

Android uses the methods described in this section to call into your activity as the activity transitions between the four states listed in the previous section. Some transitions may result in multiple calls to your activity, and sometimes Android will kill your application without calling it. This whole area is rather murky and probably subject to change, so pay close attention to the official Android documentation as well as this section when deciding which events deserve attention and which you can safely ignore.

Note that for all of these methods, you should chain upward and invoke the superclass’s edition of the method, or Android may raise an exception.

onCreate() and onDestroy()

We have been implementing onCreate() in all of our Activity subclasses in all the examples. This method will be called in three situations:

  • When the activity is first started (e.g., since a system restart), onCreate() will be invoked with a null parameter.
  • If the activity had been running, then sometime later was killed off, onCreate() will be invoked with the Bundle from onSaveInstanceState() as a parameter (as described in the next section).
  • If the activity had been running and you have set up your activity to have different resources based on different device states (e.g., landscape versus portrait), your activity will be re-created and onCreate() will be called. Working with resources is covered in Chapter 23.

Here is where you initialize your UI and set up anything that needs to be done once, regardless of how the activity is used.

On the other end of the life cycle, onDestroy() may be called when the activity is shutting down, either because the activity called finish() (which “finishes” the activity) or because Android needs RAM and is closing the activity prematurely. Note that onDestroy() may not be called if the need for RAM is urgent (e.g., an incoming phone call), but the activity will still be shut down. Hence, onDestroy() is mostly for cleanly releasing resources you obtained in onCreate() (if any).

Take care when dealing with an activity that includes a view populated with an adapter from a database such as SQLite. It’s prudent to call close() on your database and/or adapter objects, but also remember that you can’t rely on these being called in onDestroy() if your shutdown is of the abrupt kind. We’ll discuss this further in Chapter 32.

onStart(), onRestart(), and onStop()

An activity can come to the foreground either because it is first being launched or because it is being brought back to the foreground after having been hidden (e.g., by another activity or by an incoming phone call). The onStart() method is called in either of those cases.

The onRestart() method is called in the case where the activity had been stopped and is now restarting.

Conversely, onStop() is called when the activity is about to be stopped.

onPause() and onResume()

The onResume() method is called just before your activity comes to the foreground, either after being initially launched, after being restarted from a stopped state, or after a pop-up dialog box (e.g., an incoming call) is cleared. This is a great place to refresh the UI based on things that may have occurred since the user was last looking at your activity. For example, if you are polling a service for changes to some information (e.g., new entries for a feed), onResume() is a fine time to both refresh the current view and, if applicable, kick off a background thread to update the view (e.g., via a Handler).

Conversely, anything that steals your user away from your activity—typically, the activation of another activity—will result in your onPause() method being called. Here, you should undo anything you did in onResume(), such as stopping background threads, releasing any exclusive-access resources you may have acquired (e.g., camera), and the like.

Once onPause() is called, Android reserves the right to kill off your activity’s process at any point. Hence, you should not be relying on receiving any further events.

The Grace of State

Mostly, the aforementioned methods are for dealing with things at the application-general level (e.g., wiring together the last pieces of your UI in onCreate() or closing down background threads in onPause()).

However, a large part of the goal of Android is to have a patina of seamlessness. Activities may come and go as dictated by memory requirements, but ideally, users are unaware that this is going on. If, for example, a user was using a calculator, took a lunch break, and returned to that calculator, he should see whatever number he was working on before the break, unless he took some action to close down the calculator (e.g., pressed the Back button to exit it).

To make all this work, activities need to be able to save their application-instance state, and to do so quickly and cheaply. Since activities could be killed off at any time, activities may need to save their state more frequently than you might expect. Then, when the activity restarts, the activity should get its former state back, so it can restore the activity to the way it appeared previously. Think of it as establishing a bookmark, such that when the user returns to that bookmark, you can restore the application to the same state that it was in when the user left it.

Saving instance state is handled by onSaveInstanceState(). This supplies a Bundle, into which activities can pour whatever data they need (e.g., the number showing on the calculator’s display). This method implementation needs to be speedy, so do not try to be fancy—just put your data in the Bundle and exit the method.

That instance state is provided to you again in two places: in onCreate() and in onRestoreInstanceState(). It is your choice when you wish to reapply the state data to your activity—either callback is a reasonable option.

The built-in implementation of onSaveInstanceState() will save likely mutable state from a subset of widgets. For example, it will save the text in an EditText, but it will not save the status of whether a Button is enabled or disabled. This works as long as the widgets are uniquely identified via their android:id attributes.

Hence, if you implement onSaveInstanceState(), you can either chain upward and leverage the inherited implementation or not chain upward and override the inherited implementation. Similarly, some activities may not need onSaveInstanceState() to be implemented at all, as the built-in one handles everything that is needed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.187.15