This article is excerpted from Sams Teach Yourself Android Application Development in 24 Hours, reprinted with permission of Sams Publishing. Coyright Lauren Darcey and Shane Conder, all rights reserved.
Every platform technology uses different terminology to describe its application components. The three most important classes on the Android platform are Context, Activity and Intent. While there are other, more advanced, components developers can implement, these three components form the building blocks for each and every Android application. In this article, we focus on understanding how Android applications are put together. We also take a look at some handy utility classes that can help developers debug applications.
An Android application is a collection of tasks, each of which is called an activity. Each activity within an application has a unique purpose and user interface. To understand this more fully, imagine a theoretical game application called Chippy's Revenge.
Designing application features
The design of the Chippy's Revenge game is simple. It has five screens:
- Splash - This screen acts as a startup screen, with the game logo and version. It might also play some music.
- Menu - On this screen, a user can choose from among several options, including playing the game, viewing the scores, and reading the help text.
- Play - This screen is where game play actually takes place.
- Scores - This screen displays the highest scores for the game (including high scores from other players), providing players with a challenge to do better.
- Help - This screen displays instructions for how to play the game, including controls, goals, scoring methods, tips, and tricks.
Starting to sound familiar? This is the prototypical design of just about any mobile application, game or otherwise, on any platform.
Certainly, you are free to implement any kind of user interface you desire. There are no real user interface requirements on the Android platform, other than that the application must be stable, responsive and play nice with the rest of the Android system. That said, the best and most popular applications leverage the users' existing experience with user interfaces. It's best to improve upon those features, when necessary, rather than reinvent them, so you don't force the user to exert time and effort to learn your application in order to use it properly.
Determining application activity requirements
You need to implement five activity classes, one for each feature of the game:
- SplashActivity - This activity serves as the default activity to launch. It simply displays a layout (maybe just a big graphic), plays music for several seconds and then launches MenuActivity.
- MenuActivity - This activity is pretty straightforward. Its layout has several buttons, each corresponding to a feature of the application. The onClick() handlers for each button trigger cause the associated activity to launch.
- PlayActivity - The real application guts are implemented here. This activity needs to draw stuff onscreen, handle various types of user input, keep score and generally follow whatever game dynamics the developer wants to support.
- ScoresActivity - This activity is about as simple as SplashActivity. It does little more than load a bunch of scoring information into a TextView control within its layout.
- HelpActivity - This activity is almost identical to ScoresActivity, except that instead of displaying scores, it displays help text. Its TextView control might possibly scroll.
Each activity class should have its own corresponding layout file stored in the application resources. You could use a single layout file for ScoresActivity and HelpActivity, but it's not necessary. If you did, though, you would simply create a single layout for both and set the image in the background and the text in the TextView control at runtime, instead of within the layout file.
Implementing application functionality
We've talked about how each activity has its own user interface, defined within a separate layout resource file. You might be wondering about implementation hurdles such as the following:
- How do I control application state?
- How do I save settings?
- How do I launch a specific activity?
With our theoretical game application in mind, it is time to dive into the implementation details of developing an Android application. A good place to start is the application context.
Using the application context
The application context is the central location for all top-level application functionality. You use the application context to access settings and resources shared across multiple activity instances.
You can retrieve the application context for the current process by using the getApplicationContext() method, like this:
Context context = getApplicationContext();
Because the Activity class is derived from the Context class, you can use this instead of retrieving the application context explicitly.
You might be tempted to just use your Activity context in all cases. Doing so can lead to memory leaks, though. The subtleties of why this happens are beyond the scope of this article, but there is a great official Android blog post on this topic.
Once you have retrieved a valid application context, you can use it to access application-wide features and services.
Retrieving Application Resources
You can retrieve application resources by using the
getResources() method of the application context. The most straightforward way to retrieve a resource is by using its unique resource identifier, as defined in the automatically generated R.java class. The following example retrieves a String instance from the application resources by its resource ID:
String greeting = getResources().getString(R.string.hello);
Accessing Application Preferences
You can retrieve shared application preferences by using the
getSharedPreferences() method of the application context. You can use the SharedPreferences class to save simple application data, such as configuration settings. Each SharedPreferences object can be given a name, allowing you to organize preferences into categories or store preferences all together in one large set.
For example, you might want to keep track of each user's name and some simple game state information, such as whether the user has credits left to play. The following code creates a set of shared preferences called GamePrefs and saves a few such preferences:
SharedPreferences settings = getSharedPreferences("GamePrefs", MODE_PRIVATE);
SharedPreferences.Editor prefEditor = settings.edit();
To retrieve preference settings, you simply retrieve SharedPreferences and read the values back out:
SharedPreferences settings = getSharedPreferences("GamePrefs", MODE_PRIVATE);
String userName = settings.getString("UserName", "Chippy Jr. (Default)");
Accessing other application functionality using contexts
The application context provides access to a number of top-level application features. Here are a few more things you can do with the application context:
- Launch Activity instances
- Retrieve assets packaged with the application
- Request a system-level service provider (for example, location service)
- Manage private application files, directories and databases
- Inspect and enforce application permissions
The first item on this list - launching Activity instances - is perhaps the most common reason you will use the application context.
Working with Activities
The Activity class is central to every Android application. Much of the time, you'll define and implement an activity for each screen in your application.
In the Chippy's Revenge game application, you have to implement five different Activity classes. In the course of playing the game, the user transitions from one activity to the next, interacting with the layout controls of each activity.
There are a number of ways to launch an activity, including the following:
- Designating a launch activity in the manifest file
- Launching an activity using the application context
- Launching a child activity from a parent activity for a result
Designating a launch activity in the manifest file
Each Android application must designate a default activity within the Android manifest file. In the manifest file of a Droid1 project, DroidActivity might be designated as the default activity.
Other Activity classes might be designated to launch under specific circumstances. You manage these secondary entry points by configuring the Android manifest file with custom filters.
In Chippy's Revenge, SplashActivity would be the most logical activity to launch by default.
Launching activities using the application context
The most common way to launch an activity is to use the startActivity() method of the application context. This method takes one parameter, called an intent. We will talk more about the intent in a moment, but for now, let's look at a simple startActivity() call.
The following code calls the startActivity() method with an explicit intent:
startActivity(new Intent(getApplicationContext(), MenuActivity.class));
This intent requests the launch of the target activity, named MenuActivity, by its class. This class must be implemented elsewhere within the package.
Because the MenuActivity class is defined within this application's package, it must be registered as an activity within the Android manifest file. In fact, you could use this method to launch every activity in your theoretical game application; however, this is just one way to launch an activity.
Launching an Activity for a Result
Sometimes an activity wants to launch a related activity and get the result, instead of launching an entirely independent activity. In this case, you can use the
Activity.startActivityForResult() method. The result will be returned in the Intent parameter of the calling activity's
onActivityResult() method. We will talk more about how to pass data using an Intent parameter in a moment. Next: Managing activity state
Managing activity state
Applications can be interrupted when various higher-priority events, such as phone calls, take precedence. There can be only one active application at a time; specifically, a single application activity can be in the foreground at any given time.
Android applications are responsible for managing their state, as well as their memory, resources and data. The Android operating system may terminate an activity that has been paused, stopped or destroyed when memory is low. This means that any activity that is not in the foreground is subject to shutdown. In other words, an Android application must keep state and be ready to be interrupted and even shut down at any time.
Using activity callbacks
The Activity class has a number of callbacks that provide an opportunity for an activity to respond to events such as suspending and resuming. The table below lists the most important callback methods.
Key callback methods of Android Activities
|onCreate()||Called when an activity starts or restarts.||Initializes static activity data. Binds to data or resources required.|
|Sets layout with setContentView().|
|onResume()||Called when an activity becomes the foreground activity.||Acquires exclusive resources. Starts any audio, video, or animations.|
|onPause()||Called when an activity leaves the foreground.||Saves uncommitted data.Deactivates or releases exclusive resources.|
|Stops any audio, video, or animations.|
|onDestroy()||Called when an application is shutting down.||Cleans up any static activity data. Releases any resources acquired.|
The main thread is often called the UI thread, because this is where the processing for drawing the UI takes place internally. An activity must perform any processing that takes place during a callback reasonably quickly, so that the main thread is not blocked. If the main UI thread is blocked for too long, the Android system will shut down the activity due to a lack of response. This is especially important to respond quickly during the onPause() callback, when a higher-priority task (for example, an incoming phone call) is entering the foreground.
The image below shows the order in which activity callbacks are called.
Saving activity state
An activity can have private preferences - much like shared application preferences. You can access these preferences by using the getPreferences() method of the activity. This mechanism is useful for saving state information. For example, PlayActivity for your game might use these preferences to keep track of the current level and score, player health statistics and game state.
Shutting Down Activities
To shut down an activity, you make a call to the finish() method. There are several different versions of this method to use, depending whether the activity is shutting itself down or shutting down another activity.
Within your game application, you might return from the Scores, Play and Help screens to the Menu screen by finishing ScoresActivity, PlayActivity or HelpActivity.
Working with Intents
An Intent object encapsulates a task request used by the Android operating system. When the startActivity() method is called with the Intent parameter, the Android system matches the Intent action with appropriate activity on the Android system. That activity is then launched.
The Android system handles all intent resolution. An intent can be very specific, including a request for a specific activity to be launched, or somewhat vague, requesting that any activity matching certain criteria be launched. For the finer details on intent resolution, see the Android documentation.
Passing information with intents
Intents can be used to pass data between activities. You can use an intent in this way by including additional data, called extras, within the intent.
To package extra pieces of data along with an intent, you use the putExtra() method with the appropriate type of object you want to include. The Android programming convention for intent extras is to name each one with the package prefix (for example,
For example, the following intent includes an extra piece of information, the current game level, which is an integer:
Intent intent = new Intent(getApplicationContext(), HelpActivity.class);<br> intent.putExtra("com.androidbook.chippy.LEVEL", 23);<br> startActivity(intent);
When the HelpActivity class launches, the getIntent() method can be used to retrieve the intent. Then the extra information can be extracted using the appropriate methods. Here's an example:
Intent callingIntent = getIntent();<br> int helpLevel = callingIntent.getIntExtra("com.androidbook.chippy.LEVEL", 1);
This little piece of information could be used to give special Help hints, based on the level.
For the parent activity that launched a subactivity using the startActivityForResult() method, the result will be passed in as a parameter to the onActivityResult() method with an Intent parameter. The intent data can then be extracted and used by the parent activity.
Using intents to launch other applications
Initially, an application may only be launching activity classes defined within its own package. However, with the appropriate permissions, applications may also launch external activity classes in other applications.
There are well-defined intent actions for many common user tasks. For example, you can create intent actions to initiate applications such as the following:
- Launching the built-in web browser and supplying a URL address
- Launching the web browser and supplying a search string
- Launching the built-in Dialer application and supplying a phone number
- Launching the built-in Maps application and supplying a location
- Launching Google Street View and supplying a location
- Launching the built-in Camera application in still or video mode
- Launching a ringtone picker
Recording a sound
Here is an example of how to create a simple intent with a predefined action (ACTION_VIEW) to launch the web browser with a specific URL:
Uri address = Uri.parse("http://www.perlgurl.org");<br> Intent surf = new Intent(Intent.ACTION_VIEW, address);<br> startActivity(surf);
This example shows an intent that has been created with an action and some data. The action, in this case, is to view something. The data is a uniform resource identifier (URI), which identifies the location of the resource to view.
For this example, the browser's activity then starts and comes into foreground, causing the original calling activity to pause in the background. When the user finishes with the browser and clicks the Back button, the original activity resumes.
Applications may also create their own intent types and allow other applications to call them, allowing for tightly integrated application suites.
The OpenIntents.org website keeps a list of intent actions at www.openintents.org/en/intentstable. This list includes those built into Android as well as those available from third-party applications.
Working with dialogs
Handset screens are small, and user interface real estate is valuable. Sometimes you want to handle a small amount of user interaction without creating an entirely new activity. In such instances, creating an activity dialog can be very handy. Dialogs can be helpful for creating very simple user interfaces that do not necessitate an entirely new screen or activity to function. Instead, the calling activity dispatches a dialog, which can have its own layout and user interface, with buttons and input controls.
Important dialog methods of the activity class
|Activity.showDialog()||Shows a dialog, creating it if necessary.|
|Activity.onCreateDialog()||Is a callback when a dialog is being created for the first time and added to the activity dialog pool.|
|Activity.onPrepareDialog()||Is a callback for updating a dialog on-the-fly. Dialogs are created once and can be used many times by an activity. This callback enables the dialog to be updated just before it is shown for each showDialog() call.|
|Activity.dismissDialog()||Dismisses a dialog and returns to the activity. The dialog is still available to be used again by calling showDialog() again.|
|Activity.removeDialog()||Removes the dialog completely from the|
|activity dialog pool.|
Activity classes can include more than one dialog, and each dialog can be created and then used multiple times.
There are quite a few types of ready-made dialog types available for use in addition to the basic dialog. These are AlertDialog, CharacterPickerDialog, DatePickerDialog, ProgressDialog, and TimePickerDialog.
You can also create an entirely custom dialog by designing an XML layout file and using the Dialog.setContentView() method. To retrieve controls from the dialog layout, you simply use the Dialog.findViewById() method.
Logging application information
Android provides a useful logging utility class called android.util.Log. Logging messages are categorized by severity (and verbosity), with errors being the most severe. The table below lists some commonly used logging methods of the Log class.
Commonly used log methods
|Log.i()||Logs informational messages|
|Log.d()||Logs debug messages|
|Log.v()||Logs verbose messages|
Excessive use of the Log utility can result in decreased application performance. Debug and verbose logging should be used only for development purposes and removed before application publication.
The first parameter of each Log method is a string called a tag. One common Android programming practice is to define a global static string to represent the overall application or the specific activity within the application such that log filters can be created to limit the log output to specific data.
For example, you could define a string called TAG, as follows:
private static final String TAG = "MyApp";</blockquote>
Now anytime you use a Log method, you supply this tag. An informational logging message might look like this:
Log.i(TAG, "In onCreate() callback method");</blockquote>
You can use the LogCat utility from within Eclipse to filter your log messages to the tag string.
You've seen how different Android applications can be designed using three application components: Context, Activity and Intent. Each Android application comprises one or more activities. Top-level application functionality is accessible through the application context. Each activity has a special function and (usually) its own layout, or user interface. An activity is launched when the Android system matches an intent object with the most appropriate application activity, based on the action and data information set in the intent. Intents can also be used to pass data from one activity to another.
In addition to learning the basics of how Android applications are put together, you've also learned how to take advantage of useful Android utility classes, such as application logging, which can help streamline Android application development and debugging.