This week we're continuing the
Starting From Scratch series. Today we're going to take a look at
Android Activities. I'll discuss what an Activity is, how you create one, the Activity life-cycle, launching an Activity programmatically, and finally I'll give a few Activity tips I've found along the way.
What Is An Activity
According to the Android documentation, an Activity is "
... a single, focused thing that the user can do." Yeah, that's pretty vague. So let's break it down.
In the early days of Android (pre-tablet) an Activity represented pretty much everything on the screen, how it got there, and how you interact with it. Basically the Activity was analogous to a "screen" in an application. If you wanted to display a different screen you either had to dynamically tear down the current screen and rebuild the new screen (very laborious) or, preferably, start a new Activity which owned the UI and interactions for the new screen. This allowed developers to encapsulate the concepts within a screen pretty nicely and manage workflow easier.
As Android matured, and tablets became mainstream, it became necessary to reuse portions of an Activity within other Activities. Thus was born the Fragment (which I'll talk about later in this series). Prior to Fragments a typical application would have many Activities. Once Fragments were introduced the number of Activities an application had were reduced from one per screen to one per workflow.
Creating an Activity
There are two steps necessary when creating an Activity. The first is to write the Java class which extends the Activity class. This class should implement any necessary life-cycle events (which are outlined below). The second step is to declare the Activity in the Android manifest. You can see an example of this by looking at the initial Activity that was created for your application in your AndroidManifest.xml.
Activity Life-cycle
An Activity has several states that it can be in. Those states are associated with creating, starting, resuming, pausing, stopping, or destroying the Activity.
Creating
When an Activity if first being created a call will be made to the Activities
onCreate method. The onCreate method is responsible for associating a UI layout with the Activity. This is done via a call to the
setContentView method with the associated layout ID. As mentioned previously in this series, a layout is a composition of the UI elements to display on screen.
For Example:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
If you have any state that needs to be restored before the official call to
onRestoreInstanceState you can do it after the call to setContentView using the saved instance state Bundle passed in. The typical reasons you may want state restored here is if you want to be able to make any decisions on the other life-cycle methods based on the current state of the Activity. Because of this, the
onCreate method is passed a Bundle which will contain any state that was saved when the Activity was paused.
You cannot assume that the Bundle passed in to the
onCreate method will exist. In the case that there is no previous state or if it's the first time the Activity is run the Bundle will be null. Therefore it is very important to check to make sure the Bundle exists before you try to use it. If the Bundle exists you can use the information you've saved in it to restore the internal state of the Activity.
NOTE: It is really important to draw the distinction here between resetting the internal state of an Activity and resetting the UI of an Activity. YOU SHOULD NOT try to interact with the UI in the
onCreate method. The
onCreate method is called when the Activity is starting but before it is displayed on the screen. If you try to get a handle to UI elements they will not exist.
Restarting
The
onCreate method is only called when the Activity is not already in memory. Often it is the case that the Activity has been paused but not cleared out of memory. In this case when the Activity is about to be re-started the
onRestart method is called. For most people there really isn't anything you need to do in
onRestart. The internal state of your Activity will be the same as when it was paused, so there is nothing to really restore. The exception being if you are using a
Cursor.
@Override
public void onRestart() {
}
Starting
The
onStart method is called after either
onCreate or
onRestart when the Activity is visible to the user. The Activity UI is not yet ready to be interacted with. At this point you still don't want to do anything programmatically with UI elements but you are able to reset internal Activity data.
@Override
public void onStart() {
}
Resuming
Finally, we're at the point in the Activity life-cycle where you can do something with the UI. The
onResume method is called right after the Activity has been displayed on the screen. At this point the UI is ready to be interacted with. If you did not register your UI event listeners in the layout file this is where you would want to register those listeners.
@Override
public void onResume() {
}
At this point in the life-cycle your Activity is considered to be running.
Pausing
When your Activity is about to go into the background, but it is still active, the
onPause method is called. This happens when another Activity is about to be put on top of your Activity (while it's still running) or your Activity is about to be put into the background or killed.
@Override
public void onPause() {
}
This is a good time to commit changes to data and unwire any listeners that you've set up. It's important to note that
onPause doesn't necessarily mean that your Activity is going into the background. This will also be called when a dialog is displayed on top of your Activity. In this case the next life-cycle event will be
onResume instead of
onStop.
It's important that this method returns very quickly as the
onResume method for the Activity about to show will not get called until this method returns.
Stopping
The
onStop method is called when another Activity has come to the foreground and fills the entire screen. On stop cause be used to save state as well as stop things that are time intensive.
@Override
public void onStop() {
}
Destroying
The
onDestroy method is called right before your Activity is about to be removed from memory. This is a good time to clean up the internal handles that your Activity may have.
@Override
public void onDestroy() {
}
Saving State
In the previous life-cycle events I mentioned saving/restoring Activity state several times. Users will expect an Activity to be in the same state that they left it in. The user can leave the Activity for a variety of reasons like to answer a phone call or to use another app. Sometimes when a user has a lot of applications running or is doing something very memory intensive Android needs to completely remove the Activity from memory when it's not on the screen. In that case displaying the Activity again will cause it to re-display as if it was never on the screen to begin with. This is why it is important to make sure you restore the internal Activity state if there is any to restore
Saving state is done via the
onSaveInstanceState method. Restoring state is done via the
onRestoreInstanceState method. The
onSaveInstanceState method is called before the Activity is killed. If
onSaveInstanceState is called, it will be called before the
onStop life-cycle event is called. The
onSaveInstanceState is passed a Bundle which should be used to save instance state too. That bundle will then be passed back to the
onCreate life-cycle event.
onRestoreInstanceState is called after
onStart and is used to restore any state saved in the call to
onSaveInstanceState. For example:
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString("SomeVariable", someVariable);
}
@Override
public void onRestoreInstanceState(Bundle savedState) {
if(savedState != null) {
this.someVariable = savedState.getString("SomeVariable");
}
}
Launching an Activity
There are two main ways to launch an Activity. The first way is to specify the type of action you want performed and allowing the user to select the appropriate application they want to handle that. This is commonly used when sharing data or launching a url.
private void openUrlInBrowser(String url) {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
this.startActivity(intent);
}
The second way to launch an Activity is by class name. This is the case when you want to launch a very specific Activity. Typically this is how you would launch another Activity within your application.
private void openSomeOtherActivity() {
Intent intent =
new Intent(
this, SomeOtherActivity.class);
this.startActivity(intent);
}
In either case launching an Activity is a two step process. The first step is to create an
Intent which details what you want to do. You decide how you want to launch the Activity based on the
Intent constructor you select. The second step is to call the
startActivity method from your Activity.
Activity Tips
- Only restore an Activities internal state in onCreate. Never try to restore UI.
- The first time an Activity is being displayed, the Bundle passed into onCreate will be null.
- Reset an Activities UI in onResume.
- Don't change the name of the Activity used to start the application. Changing that will cause the any home screen icons associated with the previous Activity to be broken after the application is updated. The is because the icons are associated with the previous Activity name.