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.