similar to the post()
methods on Handler
and View
, in that it queues up a Runnable
to run on the UI thread, if you are not on the UI thread right now. If you already are on the UI thread, it invokes the Runnable
immediately. This gives you the best of both worlds: no delay if you are on the UI thread, yet safety in case you are not.
Now, the Caveats
Background threads, while eminently possible using the Android Handler
system, are not all happiness and warm puppies. Background threads not only add complexity, but they have real-world costs in terms of available memory, CPU, and battery life.
To that end, there are a wide range of scenarios you need to account for with your background thread, including
• The possibility that users will interact with your activity’s UI while the background thread is chugging along. If the work that the background thread is doing is altered or invalidated by the user input, you will need to communicate this to the background thread. Android includes many classes in the java.util.concurrent
package that will help you communicate safely with your background thread.
• The possibility that the activity will be killed off while background work is going on. For example, after starting your activity, the user might have a call come in, followed by a text message, then a need to look up a contact — all of which might be sufficient to kick your activity out of memory. Chapter 16 will cover the various events Android will take your activity through; hook the proper ones and be sure to shut down your background thread cleanly when you have the chance.
• The possibility that your user will get irritated if you chew up a lot of CPU time and battery life without giving any payback. Tactically, this means using ProgressBar
or other means of letting the user know that something is happening. Strategically, this means you still need to be efficient at what you do — background threads are no panacea for sluggish or pointless code.
• The possibility that you will encounter an error during background processing. For example, if you are gathering information off the Internet, the device might lose connectivity. Alerting the user of the problem via a Notification
and shutting down the background thread may be your best option.
CHAPTER 16
Handling Activity Lifecycle Events
While this may sound like a broken record please remember that Android devices, by and large, are phones. As such, some activities are more important that others — taking a call is probably more important to users than is playing Sudoku. And, since it is a phone, it probably has less RAM than does your current desktop or notebook.
As a result, 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 example — of how an activity’s lifecycle will affect your own application logic. This chapter covers the various states and callbacks that make up an activity’s lifecycle and how you can hook into them appropriately.
Schroedinger’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’re 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. For example, if a call comes in, the user will get the opportunity to take the call or ignore it.
• Stopped: The activity was started by the user, is running, but it 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, only 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 will call into your activity as the activity transitions between the four states previously listed, using the methods shown in this 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 to pay attention to and which you can safely ignore.
Note that for all of these, you should chain upward and invoke the superclass’ 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 every example. This will get 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.
• 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.
Here is where you initialize your user interface and set up anything that needs to be done once, regardless of how the activity gets used.
On the other end of the lifecycle, 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 get called if the need for RAM is urgent (e.g., incoming phone call) and that the activity will just get shut down regardless. Hence,