Scheduling Operations at Recurring Intervals
Say that as soon as your Activity starts, you want to start pinging the server every minute. When the user
exits the Activity, you should stop pinging.
In the following example, I add calls to the Handler in onResume() and onPause() (see the earlier
examples in this section for the setup of the Handler instance), effectively making these happen when the
Activity is shown and dismissed. In onResume, I set the boolean for pinging the server to true and sent
a PING_SERVER message to be executed immediately (the first ping should happen as soon as possible). The
message arrives in your callback message shown in the previous example, which calls your pingServer()
method.
public class SampleActivity extends Activity implements Handler.Callback {
private static final String PING_URL = “http://www.server.com/ping”;
private static final int SIXTY_SECONDS_IN_MILLISECONDS = 60 * 1000;
public static final int SYNC_DATA = 10;
public static final int PING_SERVER = 20;
private Handler mHandler;
private boolean mPingServer = false;
private int mFailedPings = 0;
... code from previous examples omitted for brevity
@Override
protected void onResume() {
super.onResume();
mPingServer = true;
mHandler.sendEmptyMessage(PING_SERVER);
}
@Override
protected void onPause() {
super.onPause();
mPingServer = false;
mHandler.removeMessages(PING_SERVER);
}
private void pingServer() {
HttpURLConnection urlConnection
try {
URL pingUrl = new URL(PING_URL);
urlConnection = (HttpURLConnection) pingUrl.openConnection();
urlConnection.setRequestMethod(“GET”);
urlConnection.connect();
if(urlConnection.getResponseCode() == 200) {
mFailedPings = 0;
} // Here you should also handle network failures...
} catch (IOException e) {
// Network error should be handled here as well...
} finally {
if(urlConnection != null) urlConnection.disconnect();
}
Chapter 2: Efficient Java Code for Android 51
if(mPingServer) {
mHandler.sendEmptyMessageDelayed(PING_SERVER,
SIXTY_SECONDS_IN_MILLISECONDS);
}
}
}
In pingServer(), you make a simple HTTP call to see if your server is alive. Once your call is completed, you
check whether you should keep pinging the server, and if so, you schedule a new message to be processed in
60 seconds. In the onPause() method, you change the boolean to false and then remove any pending
messages with the what field set to PING_SERVER.
Using the MainLooper with a Handler
Because you assign a thread to a Handler by giving it a Looper object in the constructor, you can create a
Handler that processes messages on the main thread. Doing so is especially useful when you want to avoid
using the runOnUiThread() method, which tends to result in rather ugly and less optimal code if used often.
I use this pattern frequently in my applications so that I can simply send messages between the main thread
and the thread used for background operations.
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case SYNC_DATA:
syncDataWithServer(message.obj);
break;
case SET_PROGRESS:
ProgressBar progressBar =
(ProgressBar) findViewById(R.id.progressBar);
progressBar.setProgress(message.arg1);
progressBar.setMax(message.arg2);
break;
}
message.recycle();
return true;
}
In the preceding handleMessage example, you can receive two types of messages, SYNC_DATA and SET_
PROGRESS. The first one needs to run on a separate thread, whereas the second one must run on the main
thread because it will update the UI. To do this, you create an additional Handler object that will be used to
send messages that are processed on the main thread.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mMainHandler = new Handler(getMainLooper(), this);
HandlerThread handlerThread = new HandlerThread(“BackgroundThread”);
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper(), this);
}
52 Part I: Building a Better Foundation
Notice that this is basically the same onCreate method as shown earlier. The exception is the line where you
create mMainHandler. Instead of starting a new HandlerThread, you simply retrieve the Looper for
the main thread. This doesn’t affect how the main thread is running; you just connect an additional Handler
and callback to the main thread. Messages posted to this Handler are processed by the same callback as the
second Handler you create for background operations. When you want to update the ProgressBar, you
send a simple message, as shown here:
Message.obtain(mMainHandler, SET_PROGRESS, progress, maxValue).
sendToTarget();
You can use this approach for any operation that must be executed on the main thread. You can either send
simple Message objects as just shown or pass along more complex data in the obj field or as a Bundle in
setData. You just need to make sure that you post messages to the correct Handler.
Picking the Right Solution for Threads
I’ve now shown three different methods for creating and using threads on Android. There are other utilities in
the API for doing this as well, such as the ExecutorService and the Loader. The ExecutorService is
useful if you need to have multiple operations running in parallel, which is usually the situation when writing
server-side applications responding to multiple clients. This Service is also used behind the scenes in
AsyncTask, and if you want to be able to execute multiple AsyncTasks in parallel, you can do so using the
right ExecutorService.
The three preceding examples are the ones to start with when you need a dedicated thread for an operation.
Using the Thread class directly is discouraged unless you need full control of the entire execution of the
thread. AsyncTask and Handler are recommended in most cases, and which one you choose depends
on your needs. If the operation isn’t performed frequently, like more than once every minute, AsyncTask is
probably a good choice. If you need to schedule operations or need to do something at a fast, recurring interval,
Handler is a better choice. Working with the Handler tends to generate less code in the long run, whereas
AsyncTask is easier to use.
Summary
In this chapter, I covered some of the advanced Java features in Java SE 5.0 that with the modern JIT-enabled
Dalvik VM are now safe to use on Android. Understanding and using these features will likely simplify your code,
which makes the code easier to test and maintain. I also showed how to use the concurrency API from java.
util.concurrent, instead of implementing your own queues or locks. Whenever you reinvent the wheel
by implementing your own version of a basic class, you’re making a common but big mistake: You’ll have more
code to test, more code that can cause bugs, and more code to maintain.
I also explained how to avoid many pitfalls when it comes to memory allocations. If your code creates a lot
of temporary and short-lived objects, your application will most likely perform badly in the user interface.
Understanding how to efficiently and safely reuse objects allows for a much smoother user experience.
Chapter 2: Efficient Java Code for Android 53
To conclude the chapter, I covered three methods for using threads on Android but recommended using only
two of them (AsyncTask and Handler). Multithreading is a complex topic and often the cause of many bugs
that are hard to find. Always try to use the ready-made utility classes for threads because they will make things
simpler and allow you to focus on the functions of your own code.
Java is a powerful language that makes it easier for developers to express what they want to achieve and
learning how to use the language most efficiently will make you a better developer and help you create high-
quality code.
Further Resources
Documentation
I recommend reading the performance tips chapter at: http://developer.android.com/
training/best-performance.html
Books
Bloch, Joshua. Effective Java, 2nd Edition . Addison-Wesley, 2008.
Online Sources
Google IO video sessions on YouTube at: www.youtube.com/user/GoogleDevelopers
Part IIGetting the Most
Out of Components
Chapter 3 Components, Manifests, and Resources
Chapter 4 Android User Experience and Interface Design
Chapter 5 Advanced User Interface Operations
Chapter 6 Services and Background Tasks
Chapter 7 Android IPC
Chapter 8 Mastering BroadcastReceivers and Configuration Changes
Chapter 9 Data Storage and Serialization Techniques
Chapter 10 Writing Automated Tests
Chapter 3
Components, Manifests,
and Resources
So far I’ve covered the more general aspects of development, much of which you can apply to generic
Java development as well. In this chapter, I start going through some more Android-specific information.
( Note: I’m assuming that you’re familiar with the basic concepts of Android and have already written
applications for this platform.)
The three core concepts of any Android application are the components, the manifest, and the resources. Every
Android application uses all of these, so you need to fully understand them. Although your IDE will most likely
assist you in setting up the basics, you can do a lot more by optimizing them yourself.
I start with an overview of the Android components and how to use them optimally for the software
architecture of your applications. Next, I cover some of the details of the Android manifest and explain how you
can fine-tune the parameters to suit your application. Finally, I cover some advanced details of the resources
and assets and how you can work with these.
Android Components
When you write an Android application, you usually start by defining a main Activity. In fact, your IDE
will probably ask you for the name of the main Activity and create it for you. You continue by setting up
Services, BroadcastReceivers, and ContentProviders and then tie them all together using the
Intents. The common name for these parts is components.
These four types of components (Activity, Services, BroadcastReceivers, and
ContentProviders) are the ones most frequently used. Activities are responsible for the user interface,
Services implement operations running in the background, BroadcastReceivers listen for system
events, and ContentProviders store application data.
They all come with a base class that you extend and a section in the application manifest XML file that exposes
them to the Android system. There is also a fifth type of component with the name Application that, though
rarely utilized, is useful in some situations.
Allow me to walk you through these five components and put them into context before moving on to the
software architecture for a standard Android application. (I cover each component in more detail in later
chapters, as indicated in the following sections.)
58 Part II: Getting the Most Out of Components
The Activity Component
User interfaces for an Android application are managed by extensions of the Activity class. Your application
can have several Activities for different functions, but only one Activity can be displayed at any given
time. As with all other components, a number of lifecycle callbacks will notify you of the current state.
The general guide regarding Activities is that they handle only UI-related operations. Although you can
use AsyncTask or Handler (as I describe in Chapter 2) to execute things off the main thread, the preferred
practice is to always delegate long-running operations to a Service and execute them on a separate
thread there—because the state of an Activity is very much controlled by the user, and it becomes a bit
complicated if you need to cancel a running operation because the user happens to press the Home button.
Instead, let a Service handle these operations and focus on the user interface in your Activities.
Starting with Android 3.0 (Honeycomb), the Fragments API became available for building dynamic user
interfaces. This API was specifically designed to allow application developers to implement user interfaces
that will adapt to the size of the devices they’ll be running on. Instead of simply scaling the entire application
when running on a 10-inch tablet, you can use Fragments to show more details than when running the same
application on a 4-inch device.
The Service Component
The second most-common component is the Service. Basically, anything that doesn’t involve normal user-
interface operations goes into a Service. Remember that all components run on the same main thread, so
you still have to make sure that your potentially long-running operations are executed on a separate thread
using either a Handler or an AsyncTask. You want to move these operations to a Service, and not simply
keep them in a background thread inside your Activity, because you want to complete the operation even
if the user presses the Back or Home button during the Activity. By allowing a Service to control long-
running operations, you can more easily keep track of the state of these operations.
I recommend that each task have a dedicated Service. You can use one Service for storing data and
another one for communicating with an online web Service. For instance, if you’re building a music player,
create one Service for the playback and another Service for tasks that aren’t related to music. You want
different Services for different operations so that Services can be started and restarted differently; it’s
easier to have multiple Services than to try to build one Service that handles everything.
You learn more about Services and background operations on Android in Chapter 6.
The BroadcastReceiver Component
BroadcastReceivers are special components because they are stateless, which means that the
BroadcastReceiver object is valid only during the onReceive() call. Therefore, you can’t keep a
reference to the BroadcastReceiver instance that’s declared in the manifest anywhere in your code.
Also, you can’t add the instance as a listener or callback to an asynchronous operation. Basically, the only
thing you can and should do in the onReceive() method of a BroadcastReceiver is to delegate
the call to another component, either through the Context.startActivity() or the Context.
startService() method.
Chapter 3: Components, Manifests, and Resources 59
This limitation makes BroadcastReceivers useful for one thing only: listening to system events. Many
BroadcastIntents are defined in the Android SDK, and they’re spread out in different classes in the API. All
you can do is check the part of the API you’re interested in to see if a BroadcastIntent is there that provides
what you’re looking for.
The BroadcastReceiver component is also a bit special because it can also be programmatically declared
inside a Service or an Activity. These instances are manually registered and unregistered from the system
in your code. Always unregister a programmatically defined BroadcastReceiver or you will leak a reference
and waste memory.
A programmatically defined BroadcastReceiver is sometimes the only way you can listen for a
certain broadcast. Some BroadcastIntents don’t allow you to register them through the manifest. For
instance, the broadcast defined by Intent.ACTION_BATTERY_CHANGED can be received only from a
BroadcastReceiver registered with Context.registerReceiver().
You find out more about BroadcastReceivers in Chapter 8.
The ContentProvider Component
You don’t need to define a ContentProvider in order to store data for your Android application. In many
cases, a simple key/value storage using SharedPreferences is sufficient, and you can store data in an
SQLite database using the SQLite API directly from your Services and Activities. Storing files inside your
application’s data folder is another way of persisting application data.
However, if the application data you’re going to store is suitable for SQL, it’s usually easier to implement
a ContentProvider even if you won’t be sharing the data with other applications. Doing so becomes
especially useful when you want to display the application data using an AdapterView (like a list or a grid)
because the Loader API provides readymade implementations for loading data from a ContentProvider.
I go into the details of different data storage techniques for Android in Chapter 9.
The Application Component
There is also a fifth component, simply called Application , that is rarely used but can come in handy
sometimes. You can consider the Application component as a top-level component that’s created before
Activities, Services, and BroadcastReceivers.
Your Android app will always have an Application component, and unless you define one, a default one
will be created for you. You can always retrieve a reference to the Application component through the
method Context.getApplication(). Because all Android apps will have one and only one instance of
this component, you can use it to share variables and communicate across the other components within your
app. Although sharing a global state can be solved using a singleton class as well, using the Application
component has the advantage that it also implements application lifecycle callbacks.
The following code exemplifies code for a custom Application component. This example also shows how
to use this component for sharing global variables and notifying listeners whenever these variables are added,
changed, or removed. Although simplistic, this example demonstrates how you can utilize an already-existing
Android component to solve a problem that would otherwise require a singleton class.
60 Part II: Getting the Most Out of Components
public class MyApplication extends Application {
private ConcurrentHashMap<String, String> mGlobalVariables;
private Set<AppStateListener> mAppStateListeners;
@Override
public void onCreate() {
super.onCreate();
// Called before any other component is created
mGlobalVariables = new ConcurrentHashMap<String, String>();
mAppStateListeners = Collections.synchronizedSet(new
HashSet<AppStateListener>());
}
public String getGlobalVariable(String key) {
return mGlobalVariables.get(key);
}
public String removeGlobalVariable(String key) {
String value = mGlobalVariables.remove(key);
notifyListeners(key, null);
return value;
}
public void putGlobalVariable(String key, String value) {
mGlobalVariables.put(key, value);
notifyListeners(key, value);
}
public void addAppStateListener(AppStateListener appStateListener) {
mAppStateListeners.add(appStateListener);
}
public void removeAppStateListener(AppStateListener appStateListener)
{
mAppStateListeners.remove(appStateListener);
}
private void notifyListeners(String key, String value) {
for (AppStateListener appStateListener : mAppStateListeners) {
appStateListener.onStateChanged(key, value);
}
}
public interface AppStateListener {
void onStateChanged(String key, String value);
}
}
The manifest file (AndroidManifest.xml) will always have an application element. However, in order for
Android to recognize that your custom Application component is to be used, instead of the default, you
need to declare the custom Application component in a android:name attribute (see the bold text in the
following example).
Chapter 3: Components, Manifests, and Resources 61
<application android:label=”@string/app_name”
android:icon=”@drawable/app_icon”
android:name=”.MyApplication” >
<!—- All other components are declared here -->
</application>
As just shown, you declare your custom Application component much as you declare an Activity or a
Service. Simply add the class name in the android:name attribute, and you’re set to go.
public class MyActivity extends Activity
implements MyApplication.AppStateListener {
@Override
protected void onResume() {
super.onResume();
MyApplication myApplication = (MyApplication) getApplication();
myApplication.addAppStateListener(this);
}
@Override
protected void onPause() {
super.onPause();
MyApplication myApplication = (MyApplication) getApplication();
myApplication.removeAppStateListener(this);
}
@Override
public void onStateChanged(String key, String value) {
// Handle state change...
}
}
When you need to access your custom Application component from somewhere in your code, you simply
call Context.getApplication() and cast it to your custom class, as shown in the preceding example.
Because you’re using a listener pattern in this example, make sure that you register and unregister the listener
correctly in the onResume() and onPause() methods.
Application Architecture
Generally, Android developers start a new project by creating an Activity and designing the user interface.
Although this approach is okay, my suggestion is that you first consider the overall application architecture
from a broader perspective. If you plan to do network calls, moving them to a separate Service is a
good approach. If you need to be notified about certain system broadcasts, it’s probably wise to set up a
BroadcastReceiver and decide where to delegate those events. If your application needs to store data
beyond simple key/value pairs, I suggest making a ContentProvider responsible for that scenario. Finally, if
you have a complicated application, it may be worth your time to add a custom Application component as
well to track global states and communicate between the other components.
I usually sketch an overall architecture using the components as a base. I ask myself what Activities and
Services are needed at first and then move on to consider broadcast events and ContentProviders. This
62 Part II: Getting the Most Out of Components
architecture doesn’t need to reflect the actual user interface of your application because Activities can
have a dynamic user interface with the help of Fragments. I tend to rely on the readymade extensions of the
basic components as much as possible. For instance, the PreferenceActivity class is great for building the
user interface for the settings part of your application.
Figure 3-1 shows a simple diagram that exemplifies how you can combine the components in Android to create
a well-designed architecture. By always making sure that each component handles only the operations it’s
designed for, you’ll have a stable foundation for the development of your application.
Settings
User settings
Main
Activity
Activity
Call service
Notify on
over local
data changes
Binder
Query data
Service for
Settings
background
Activity
Content
Delegate events operations
Update data
Provider
Call web service
Figure 3-1 A high-level diagram showing the relationships among components in a
typical Android application
You now have a general understanding of the components in Android, but along with the Java code that you
write to implement your own versions of these components, you also need to know how to add them to the
application manifest, which is the topic of the next section.
The Android Application Manifest
The manifest is an XML file where you define each component and declare everything else about your
application. The manifest is the core of any Android application, so it’s important to fully understand how to
structure such files. Small mistakes in manifests can cause performance issues with your application (which
could affect the entire system), unnecessary power consumption (which could cause the battery to drain), and
security issues (which could leak sensitive information to other applications), and under certain conditions, they
can cause your application to crash.
Fortunately, the lint tool (refer to Chapter 1) in the Android SDK provides inspections for the manifest file, so your
IDE will let you know about areas in the file that need to be fixed. In this section, I provide some tips that you can
use to optimize your application and that will be useful when you start doing more advanced development.
The Manifest Element
The top-level element in the AndroidManifest.xml file is named manifest. This is where the package
name, the unique identifier for your application, is defined. You can also define the Linux user ID and name that
your application will be running under, the version information about your application, and where the APK file
should be installed.
Chapter 3: Components, Manifests, and Resources 63
The following example shows the manifest tag with all the possible attributes set. The first attribute,
package, defines the unique identifier for you application in the Android system, the name of the application
process, and the name of the default task affinity for Activities. Be sure to choose the package name well
because it cannot be changed after the application is released.
<?xml version=”1.0” encoding=”utf-8”?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”com.aaptl.pushingthelimits.sample”
android:sharedUserId=”com.apptl.userid”
android:sharedUserLabel=”@string/userLabel”
android:installLocation=”auto”
android:versionCode=”1”
android:versionName=”1.0”>
</manifest>
When deciding on the package name, it’s best to use the domain name of the company or organization
that publishes the application and append a shortened, lowercase version of the name the application
will have on Google Play. If you’re working as a consultant or a freelance developer, be sure to use a
name based on your customer’s domain name, and not your own.
The android:sharedUserId and android:sharedUserLabel are the Linux user ID and name that
your application will run on. By default, these are assigned by the system, but if you set them to the same value
for all the applications you publish using the certificate, you can access the same data and even share the
process of these applications. If you’re building a suite of applications or if you have a free and a paid version,
this can be very helpful.
In regard to free and paid versions of your game, when people try your free version and decide to
purchase the paid version, they don’t want to lose all the progress they achieved before the purchase.
To solve this issue, make sure that both your versions share the same user ID and simply synchronize
the data from the free to the paid version on startup.
When multiple applications share the same process, you can save the total amount of RAM your applications
use. However, all the applications that share the same process will also crash if one of the applications
experiences a runtime error.
You can use the android:installLocation attribute to control where the application is installed. You can
install it either on the device’s internal storage (the data partition) or the external storage (for instance, the SD
card). Note: You control only the location of the APK file through this attribute. The application data is still stored
safely on the internal storage.
The version information is important when you publish your application on Google Play. android:versionCode
is the value that is read by the Google Play Store, whereas android:versionName is what is presented to
the user. My recommendation is to use a version code that makes it easy for you. The simplest solution is to start
64 Part II: Getting the Most Out of Components
at 1 and simply increment it with 1 with every new version. You can set up your build script on your continuous
integration system to increment this for each nightly build (highly recommended!), or you can increase it manually
before you commit new code to your repository. Either way, increment the value before trying to publish a new
version to Google Play.
Google Play Filters and Permissions
The next part of your manifest should contain the details about how it is made visible in Google Play and
the features in the platform you’re using. Here, you also declare the permissions you use as well as the new
permissions that your application requires when providing interfaces for other applications.
You can find more about permissions in Chapters 12. At this point, just remember to declare the permissions
you need, or you’ll get a nasty error when your application tries to access a restricted API. If your application will
provide an interface (through a Service, content provider, or custom BroadcastIntent), be sure to define
your own permissions in the manifest.
One of the most important parts of your AndroidManifest.xml file, but which is also often forgotten, is the
uses-features element. This is what Google Play uses when it filters which applications will be visible on
each device. For example, if your application needs the capability to send SMS, you probably want to exclude
the devices that lack support for this (Wi-Fi–only tablets), and add an element saying that you need telephony
support.
Also, with new types of Android devices appearing, some features we’ve come to expect on an Android device
aren’t always there. For instance, although most Android devices have a touch screen, you won’t find one on
a device that runs on TV. If your application requires a touch screen and cannot work via a mouse pointer, be
sure to declare this in your manifest. The following example shows how to specify that your application needs
telephony support and a touchscreen supporting full “Jazz Hands” multi-touch.
<uses-feature android:name=”android.hardware.microphone” />
<uses-feature android:name=”android.hardware.telephony” />
<uses-feature android:name=”android.hardware.touchscreen.multitouch.
jazzhand” />
You can find a complete list of all the standard features in Android at http://developer.android.
com/guide/topics/manifest/uses-feature-element.html#features-reference
Android supports many different screen sizes by default, but you won’t always want your application to be
available for all of them. For instance, if you’re developing an application that’s intended for tablets, you may
want to limit it to only devices with that screen size. You can do so by using the supports-screens element,
which allows you to specify which screen sizes your application works on as well as the smallest width required
for a device screen. The following is an example of what to use for a tablet-only application.
<supports-screens android:smallScreens=”false”
android:normalScreens=”false”
android:largeScreens=”false”
android:xlargeScreens=”true” />
Chapter 3: Components, Manifests, and Resources 65
Another important function of the manifest is determining the API levels your application supports.
You can define minimum, target and maximum levels: Minimum defines the lowest Android version you
support, whereas maximum defines the highest. The latter is useful when you have multiple APKs for
different Android versions for a single application or if you want to delay publishing an application for new
versions of Android until you’ve had time to verify your application. My recommendation is to avoid the
android:maxSdkVersion attribute if possible.
The interesting attribute in the uses-sdk element is the android:targetSdkVersion. This attribute
tells a device which API level you’re targeting. Although android:minSdkVersion lets you limit the lowest
Android version you support, it tells Android not to enable any compatibility behaviors with the target version.
More specifically, this combination allows you to gracefully degrade feature support in your application for
older versions while still maintaining an up-to-date user interface and functionality for later versions.
<uses-sdk android:minSdkVersion=”11” android:targetSdkVersion=”16”/>
My recommendation is to always specify android:minSdkVersion and android:targetSdkVersion,
as shown in the preceding example. Unless you specify android:minSdkVersion, it will default to 1 (that is,
Android version 1), which you probably want to avoid. By specifying android:targetSdkVersion, you can
easily increase your support for new versions.
You can find a complete list of all API levels and which Android version they represent at http://
developer.android.com/guide/topics/manifest/uses-sdk-element.html.
The Application Element
As I described earlier, there is a fifth, rarely used, type of component named Application. This component
is represented by the application element in the manifest file. Unless you provide your custom Application
class using the android:name attribute, the system default will be used.
A number of other important attributes are on the application element. Some of these attributes provide
additional functions to your application and others are only for information. I’ll go through those I consider
most important, as shown here:
<application
android:label=”@string/app_name”
android:description=”@string/app_description”
android:icon=”@drawable/app_icon”
android:name=”.MyApplication”
android:backupAgent=”.MyBackupAgent”
android:largeHeap=”false”
android:process=”com.aaptl.sharedProcess”>
<!-- activities, services, receivers and providers go here. -->
</application>
66 Part II: Getting the Most Out of Components
Because users may have hundreds of different applications installed, it helps if you provide as much information
about your application as possible to the system. I recommend that you set both the android:label and
the android:description attributes to values that are localized (that is, with translations in different
languages). The description attribute should also contain detailed text about what your application does so that
when the user looks at your app in the settings, he immediately can tell what the app does.
Eventually, users will change their smartphones, and they’ll want to be able to move all their applications,
including the data, to their new device. Fortunately, Google provides a backup Service that helps to solve
this issue, but you have to declare this in your application and implement your own backup agent. You do so
using the android:backupAgent attribute, which points to the class that implements this. I go through the
details of the backup agent in Chapter 9, but it’s a good idea to always provide this from the start so that you
don’t forget it.
If you’re building an application that requires a large amount of memory, you’ll soon run into a problem with the
default limit of the heap size of the Dalvik VM. You can solve this issue by adding the android:largeHeap
attribute to your application manifest to let the system know you require more memory. However, never add
this unless you really need to; doing so will waste resources, and also the system will terminate your application
much sooner. For most applications this attribute is not necessary and should be avoided.
If you have a suite of applications sharing the same user ID (as described earlier for the manifest element),
you can also force them to share the same process by setting the same value to the android:process
attribute. This helps to reduce the use of your applications’ resources but also leaves them all vulnerable if one
of them crashes; the most likely situation is when you have one application that supports plug-ins that can be
installed from Google Play. Note: All applications must share the same user ID and be signed with the same
certificate in order for this to work.
Finally, you have the android:theme attribute that can be set either for the entire application (in the
applications element) or on individual Activities.
Component Elements and Attributes
Each of the standard components (Activity, Service, BroadcastReceiver, and ContentProvider)
has its own elements in the manifest. While the default attributes created by Android Studio is usually good
enough for most situations, you should always review them in order to ensure you have the optimal values.
Every component you define is enabled by default. You can change this by setting
android:enabled=”false”, which will prevent them from receiving Intents. Disabled Activities
won’t show up in the application launcher, Services won’t respond to startService() calls,
BroadcastReceivers won’t listen to BroadcastIntents, and ContentProviders won’t respond to
the ContentResolver. You can change this setting in your code, which is especially efficient if you want to
make sure that parts of your application remain disabled until the user completes certain configuration steps.
In the following XML, you see two Activities declared where the second one is disabled by default. You
want the user to start and complete the setup process before you show the main Activity. You also want to
hide the setup Activity once it’s completed.
Chapter 3: Components, Manifests, and Resources 67
<activity
android:name=”.SetupActivity”
android:label=”@string/app_name_setup”
android:icon=”@drawable/app_setup_icon”
android:enabled=”true”>
<intent-filter>
<action android:name=”android.intent.action.MAIN”/>
<category android:name=”android.intent.category.LAUNCHER”/>
</intent-filter>
</activity>
<activity
android:name=”.MainActivity”
android:label=”@string/app_name”
android:icon=”@string/app_icon”
android:enabled=”false”>
<intent-filter>
<action android:name=”android.intent.action.MAIN”/>
<category android:name=”android.intent.category.LAUNCHER”/>
</intent-filter>
</activity>
The following code is a simple example of where you use the PackageManager API to toggle the enabled state
for the Activities. This way, you can change which Activity is shown in the launcher as well.
private void toggleActivities() {
PackageManager packageManager = getPackageManager();
// Enable the main activity
packageManager.setComponentEnabledSetting(new ComponentName(this,
MainActivity.class),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
// Disable the setup activity
packageManager.setComponentEnabledSetting(new ComponentName(this,
SetupActivity.class),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
Sometimes you have a component, usually a Service, that you don’t want to expose to the rest of the
system for security purposes. To do this, you can set the android:exported attribute to false, which will
effectively hide that component from the rest of the system.
If you want a component to be available for other applications but want to provide a level of security, you
can provide a permission that the calling application needs to specify in its own manifest (by using uses-
permission). Usually, you define your own permission (using a permission element under the manifest
element) and then apply it to the components that require it. You apply a permission requirement to a
component through the android:permission attribute.
68 Part II: Getting the Most Out of Components
Intent Filtering
All components in Android are accessed using Intents. An Intent is an abstract description of
an operation that you want to perform. Intents are either sent to an Activity, a Service, or a
BroadcastReceiver. Once sent, Android’s Intent resolution kicks in to decide where the Intent should
be delivered.
The first thing during Intent resolution is to determine if it is an explicit or implicit Intent. Explicit
Intents contain information about the package and the name of the component, and these can be delivered
immediately because there can be only one match. This method is generally used for application-internal
communication. Implicit Intent resolution depends on three factors: the action of the Intent, the data URI
and type, and the category. Extras and flags on Intents carry no meaning when it comes to deciding where
they should be delivered.
Action is the most important test and usually the one you should focus on. Android has a number of predefined
actions, and you can define your own actions as well. When defining your own actions, it’s customary to
prepend the string with your package name so that you don’t end up with conflicting action strings between
applications.
Data doesn’t really carry actual data but contains a URI and a MIME-type, which is useful when you want to use
an Activity to open only certain file types.
The category is mostly relevant for Activities. All implicit Intents sent by startActivity() will
always have at least one category defined (android.intent.category.DEFAULT), so unless the
intent-filter for your Activity also this category, it won’t pass the Intent resolution test. The only
exception here is for intent-filters for the launcher.
The following XML shows an Activity with two intent-filters, one for the launcher and one for
opening files with the MIME type starting with video.
<activity
android:name=”.VideoPlayer”
android:label=”@string/app_name_setup”
android:icon=”@drawable/app_setup_icon”
android:enabled=”true”>
<intent-filter>
<action android:name=”android.intent.action.MAIN”/>
<category android:name=”android.intent.category.LAUNCHER”/>
</intent-filter>
<intent-filter>
<action android:name=”android.intent.action.VIEW” />
<category android:name=”android.intent.category.DEFAULT” />
<data android:mimeType=”video/*” />
</intent-filter>
</activity>
The first intent-filter doesn’t need a category android.intent.category.DEFAULT because it
will be managed by the launcher application. The second intent-filter will match when the user triggers
a VIEW action on a video file. The file can be stored on the local storage or on a web server as long as the MIME
type starts with video.
Chapter 3: Components, Manifests, and Resources 69
You can read more about Intents and Intent resolution for Android at http://developer.
android.com/guide/components/intents-filters.html.
Resources and Assets
Although most of your development work for an application will go into the source code, there is also the
embedded content like XML layouts, icons, and text values, to name a few. This static content is either stored as
resources or assets in your application’s APK file. All resources belong to a certain type (such as layout, drawable,
and so on), whereas assets are simply generic files stored inside your application. Most of your application’s
content that is not code will be represented as resources because they are tightly integrated into the Android APIs.
The resource feature in Android is one of the most powerful features of the platform from a developer’s
standpoint. It allows you to provide multiple versions of each resource depending on screen size, localization
parameters, device capabilities, and so on. The most common solution is to use the resource feature to support
multiple languages by having several versions of the text strings in different files and to support various screen
sizes through different layouts and icons of varying sizes.
When you start to define your resources in an application, you need to keep a few rules in mind. First, always
have a default resource for every resource type in your application, which means that you need to keep default
images and icons, text strings, and layouts in a resource directory without any qualifiers. Doing so ensures that
your application won’t crash if it runs on a device with a resource qualifier that doesn’t match those you’ve
provided. The easiest way to ensure this is to start with the default resources and create the alternate versions
once you know which variations you need.
Also, use resources whenever possible and avoid hard-coded strings and values. Don’t keep strings in your
application’s code that will be printed in the user interface; instead, externalize them by putting them in the
strings.xml file. Values that can be placed in a resource file should be moved there. Doing so may require
some extra effort, but once you get used to always defining strings and other values in the resources, you’ll see
that other more complicated tasks become easier. Localization, adding support for more languages, becomes
easier if everything is defined as resources from the start. Changing sizes on fonts, margins, paddings, and other
properties becomes easier if they’re all defined in one place.
Resources are filtered using a number of qualifiers that you specify. For instance, if you want to provide a high-
resolution set of icons for devices with very high-density pixel displays, you can do so by storing a separate
set of them in a directory named drawable-xhdpi. The most common qualifiers are for screen rotation and
size, language, and region. It’s important to name the directory with the resource qualifiers in the correct order;
otherwise, Android will ignore that directory. For instance, language and region should always come before
screen size.
You can find a list of all the resource qualifiers, their order of precedence, and their meaning at
http://developer.android.com/guide/topics/resources/providing-resources.
70 Part II: Getting the Most Out of Components
You can access resources in two ways: in XML or in Java code. When accessing the resources, you don’t need to
specify qualifiers; the system handles this automatically.
Now, it’s time to take a look at some more advanced examples of using resources. I cover user-interface
resources, such as drawables, in Chapter 4 and focus on the more generic types here.
Advanced String Resources
Basically, every string in your application should be externalized into a string resource. As you can see in the
following example, several options provide an advantage over Java’s String handling and eliminate many of
the problems, especially when it comes to formatting and localization.
<?xml version=”1.0” encoding=”utf-8”?>
<resources>
<string name=”personal_welcome_message”>Welcome %s!</string>
<plurals name=”inbox_message_count”>
<item quantity=”zero”>Your inbox is completely empty!</item>
<item quantity=”one”>You one message in your inbox!</item>
<item quantity=”two”>You two messages waiting to be read!</item>
<item quantity=”few”>You have %d messages waiting!</item>
<item quantity=”many”>%1$d messages in your inbox! %2$s, you
should really login here more often!</item>
<item quantity=”other”>%1$d messages in your inbox! %2$s, you
should really login here more often!</item>
</plurals>
<string-array name=”default_categories”>
<item>Work</item>
<item>Personal</item>
<item>Private</item>
<item>Spam</item>
<item>Trash</item>
<item>Draft</item>
</string-array>
</resources>
This example defines three different types of string resources. The file should be named strings.xml
(although the name doesn’t matter as long as it ends with .xml) and placed in the resources directory named
values. You then duplicate this file for each language you support and put the file in a values-<language
qualifier> directory.
The preceding example is a simple string that takes one string parameter as its input and inserts it where the %s
is placed. The following code snippet shows how you can use the getString method to retrieve the resource
and pass a String variable as input.
public void showWelcomeMessage(String name) {
((TextView) findViewById(R.id.welcome_message_field)).
setText(getString(R.string.personal_welcome_message, name));
}
Chapter 3: Components, Manifests, and Resources 71
You can find detailed rules on formatting resource strings in the JavaDoc for the java.util.
Formatter class at http://developer.android.com/reference/java/util/
The preceding code snippet is a plurals resource that allows you to define different strings depending on the
amount of input. This is especially useful because the grammar for a language can be very hard to manage
using normal string operations. The following example shows how you first retrieve the Resources object and
then call getQuantityString to get the right string value depending on the input. This method can also
take formatting parameters if one of the choices requires that.
public void showInboxCountMessage(int inboxCount, String name) {
Resources res = getResources();
String inboxCountMessage = res.
getQuantityString(R.plurals.inbox_message_count, inboxCount,
name);
((TextView) findViewById(R.id.inbox_count_field)).
setText(inboxCountMessage);
}
The preceding example shows how to provide an array of strings. These are useful when you want to provide
an array of constant string values. In the following code, you see an example where you populate a ListView
using an ArrayAdapter with the string array declared earlier.
public void displayCategories() {
ListView listView = (ListView) findViewById(R.id.category_list);
Resources res = getResources();
String[] categories = res.getStringArray(R.array.default_categories);
ArrayAdapter<String> categoriesadapter = new
ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
categories);
listView.setAdapter(categoriesadapter);
}
Localization
As I described earlier, resources in Android can be efficiently used for providing localization support. To do so,
you copy the default string resources into a new directory with the appropriate language and region qualifier
and then start translating the text.
Although no tool is available in the Android SDK to help you with the actual translation of one language
to another, the built-in lint tool (described in Chapter 1) shows whether you have a resource directory for a
language without a translation.

72 Part II: Getting the Most Out of Components
Because you probably don’t know all the languages you want to support (if you do, please let me know so we
can be friends!), you will need some help translating your resources. Your first choice, especially if you’re on a
tight budget, is to use Google Translator Toolkit (see Figure 3-2). This is a Service from Google that allows
you to upload an Android resource XML and have it automatically translate your strings to a new language. The
result might not be perfect, but the Service is getting better all the time, thanks to the efforts of Google.
Figure 3-2 Google Translator Toolkit after translating a string.xml file from English to Swedish
You can access the Google Translator Toolkit at http://translate.google.com/toolkit.
You can also hire a professional translation service to do the work. Although the quality will most likely be much
better than when using an automatic tool, a professional service will also cost quite a bit if you have many
different languages. Also, if you update your application and add new strings in your default resources, you’ll
need to submit the new strings, further increasing the cost of developing your application.
Using Resource Qualifiers
Providing alternative resources for different screen sizes and locales (language and region) is fairly straightforward,
so I won’t cover that topic much more in this chapter. There are, however, other things you can use the resource
qualifiers for.
Chapter 3: Components, Manifests, and Resources 73
You can use Android resources in your application to control the application logic based on things that can be
expressed as resource qualifiers.
Consider the following example: You have a very popular game that you provide for free on Google Play.
The game is financed through in-game advertisement that the user can disable by doing a simple in-game
purchase. However, a major carrier has offered to buy an ad-free version of your game for all its customers.
One way to approach this issue is to build a duplicate version of the game and publish that version on Google
Play for a specific region and carrier. Although this will work technically, you’ll have to do more work because
you’ll have to publish two distinct versions of the game. Also, customers who suddenly find two versions of
the game on Google Play might become confused. A possible solution is to turn ads on or off in the game
depending on which carrier the game belongs to. You can do this programmatically in Java, but a smoother way
is to use a Boolean resource.
A great site for finding the mobile country codes (MCC) and mobile network code (MNC) values for
various carriers and countries is www.mcc-mnc.com.
The following code shows the default resource file containing the Boolean expression. Put this file in the default
values directory (that is, res/values) and then create a new resource directory with the correct qualifier. For
instance, if the carrier is Vodafone UK, the resource directory is named values-mcc234-mnc15. Then you
simply copy this resource file and change the value to true.
<?xml version=”1.0” encoding=”utf-8”?>
<resources>
<bool name=”disable_ads_by_default”>false</bool>
</resources>
Whenever the application is opened on a device with a SIM-card belonging to Vodafone UK, the following code
example returns true.
public boolean disableAdsByDefault() {
return getResources().getBoolean(R.bool.disable_ads_by_default);
}
The preceding code shows how to retrieve the resource in Java code. Although trivial, it serves as a useful
example of how powerful Android’s resource feature is. The preceding example using Boolean could be
replaced with an integer resource telling how much in-game cash a player should start with or by providing
higher-quality icons and images (using drawables with qualifiers) for customers on a certain carrier.
Using a resource with a MCC and MNC qualifier to control application logic isn’t actually secure. A
technically skilled user could bypass this check with relative ease. However, for the most part, you can
consider this safe enough. Remember, though, that filtering on MCC and MNC requires that the device
have telephony support.
74 Part II: Getting the Most Out of Components
Although the qualifiers are mostly used to provide localization and various screen size support, you can use
them in many other ways as well. Don’t be afraid to experiment with resource qualifiers, as long as you always
provide a default version as a fallback.
Using Assets
Until Android 2.3, the maximum limit of a resource file was 1MB, which caused problems if you used resources
that were larger—which is why you also had the option of storing arbitrary files in your project’s assets
directory. This limitation is no longer a problem, so you can now safely store arbitrary files in the raw resource
directory. However, because the assets directory supports subfolders, in some situations, you may still want to
use assets instead of resources.
Consider an example where you have a game and you have a number of sound effects that you want to put in
the game. You start by creating a directory in the assets folder named soundfx and place all your audio files
for the effect there.
The following code shows how to use the SoundPool API and the AssetManager to load the audio files
contained in the soundfx directory of your assets. Remember that you need to close the files that you open
from the AssetManager, or your application could leak memory.
public HashMap<String, Integer> loadSoundEffects(SoundPool soundPool)
throws IOException {
AssetManager assetManager = getAssets();
String[] soundEffectFiles = assetManager.list(“soundfx”);
HashMap<String, Integer> soundEffectMap = new HashMap<String,
Integer>();
for (String soundEffectFile : soundEffectFiles) {
AssetFileDescriptor fileDescriptor = assetManager.
openFd(“soundfx/” + soundEffectFile);
int id = soundPool.load(fileDescriptor, 1);
soundEffectMap.put(soundEffectFile, id);
fileDescriptor.close();
}
return soundEffectMap;
}
The preceding example could, of course, be changed to use raw resources as well, but I’m leaving that as an
exercise for you to explore.
Summary
I’ve now covered the three central elements that are part of any Android application: the components, the
manifest, and its resources. Understanding how these work and how to use the features they provide will take
you a long way toward becoming a master Android developer.
Try to design your application around your components because they provide lifecycle callbacks that are
managed by the system, allowing you to focus on what is important in your application. By always making the
components a first priority, you’ll find it easier to build an application without ending up with tons of boilerplate
code, something I’ve encountered far too often.
Chapter 3: Components, Manifests, and Resources 75
The manifest is the actual definition of your application, and you need to take extra care in structuring it
and the attributes you use for each element. Remember to declare all the features that your application
requires, even the ones that may be obvious, such as a touchscreen or camera. A common error that I’ve seen
during development is missing permissions. Be sure you always add a uses-permission element for the
permissions your application requires.
By using the android:enabled and android:exported attributes on selected components, you have
access to a powerful control for dynamically changing the behavior and protecting your components. You
should, at the very least, make sure none of your Services and content providers are exported, unless they
need to be accessed from other applications.
Make sure you are fully aware of how Intent resolution works. A small mistake here could cause your app to
respond in unexpected ways (or not respond at all).
When it comes to the static content in your application, move as much as possible into the resources. Make sure
every constant text string that is printed somewhere comes from the string resources, and not a constant value
in your code. Remember to define the resource in the default resource directory (that is, a directory without any
qualifiers appended to the name) and copy it to the new qualifier when needed.
Google Translator Toolkit can help you with localization of your string resources. Also consider using resources
for application logic where qualifiers like network carrier or region can be part of the factors.
Further Resources
Documentation
http://developer.android.com/guide/components/fundamentals.html
http://developer.android.com/guide/topics/manifest/manifest-intro.html
http://developer.android.com/guide/topics/resources/index.html
Chapter 4
Android User Experience
and Interface Design
Android’s user interface has changed quite a bit over the years. One of the biggest changes came with Android
3.0 (Honeycomb) where the new Holo theme was introduced. Since then, we’ve seen Android’s UI become a
polished and sleek experience that easily appeals to users of all backgrounds.
The team at Google behind the Android UI design has done some great work at explaining how to apply the
same design into your own applications. This is covered in great detail at http://developer.android.
com/design/index.html. I strongly recommend all Android developers to go through these guidelines to fully understand how to work with the different aspects of Android UI design.
In this chapter I’m going to cover UI design for Android applications at a more theoretical level. While the Android
design site I just recommended does cover many things a developer and UI designer need to know, there are still
things I believe you need to have a better understanding of when designing state-of-the-art user interfaces.
I start this chapter with a description of a process for identifying the different parts of your application UI and
how they work together. I then move on to describe Android specific UI concepts like navigation, sizes and
colors. I’ve also written a section covering usability and what you should consider when you do the detailed
design of your user interface. The final part of this chapter covers the concept of gamification and explains how
you can use this to increase the use of your application.
User Stories
The first thing you should do when you start to design your application is to write down the user stories
that describe what a user can do with your application. A user story is commonly used in agile software
development as the basis for defining product requirements. Typically, a user story uses the following form
(sometimes with a slight variation):
As a <role>, I want <goal/desire> so that <benefit>.
For instance, if you’re designing a sketching application, one of the user stories could be:
As a user, I want to change the color used by the current drawing tool so that it only affects the next use of that tool.
The final part that describes the benefit can sometimes be left out when it is obvious.
Your user stories should be brief and concrete. Each story should focus on one thing. It is better to use two
similar stories than a long and complicated one. Start with the obvious user stories, split them up, and add
more as you see fit. You will probably end up with a lot of stories once you’re done. But this process will help
78 Part II: Getting the Most Out of Components
you when you start to design your user interface as each story should be easily mapped to an action in the user
interface. Although not every user story might start with a user interaction, they will most certainly affect the
user interface in some way. For instance, a user story about an alarm is one such example:
As a user, I want the screen to display the current time when a preset alarm goes off.
User stories can then also be used to track the progress of your development work. Try to focus on completing
one story at a time and once the entire story is implemented and tested, you can move that story to a
“completed” state.
There are a few things to keep in mind when writing user stories. First of all, different stories can be
implemented using a common software component. However, this might not be obvious when you first write
a user story, but becomes apparent when you start writing your code. For instance, if your application will list
items in different categories and provide a search interface, the list of items for categories and search result can
probably use the same Activity and View layout. This is why it is a good idea to categorize your user stories
early in the process, so that you can more easily identify the places where a common Activity or View can
be used for different stories.
Understanding the User with Personas
When you’re writing the user stories, it is easy to make assumptions of how things should work based on
your own experiences and perspective. The problem is that real users lack the same knowledge about your
application that you do. The way to deal with this is to create personas which are made-up users who each
represent a typical user. For instance, if you’re designing a newsreader you can make up a number of personas
that represent who you believe are the most common users.
A persona should have a full name, description, age, sex, education and other relevant information. Also,
you should list a number of goals that the user has when using your application (for instance, catching up
on the news while commuting). Finally, you should define a priority for each persona based on their relative
importance compared to every other persona. The following is an example of a persona that you can define
when designing a newsreader application:
Name: John Smith
Sex: Male
Age: 31
Description:
◾ Commutes to work by bus where he reads news
◾ Works in an office
◾ Uses his smartphone as his primary source for reading news
Priority: High
You should define a number of personas that define the users you want to target. Try to imagine how each
persona would use your application and what their needs are.
When you have the personas for your most important users, it’s easier to define the user stories that fulfill the
most important requirements for your application. You can now easily prioritize each user story for your project.
Chapter 4: Android User Experience and Interface Design 79
Android UI Design
When planning and designing the user interface for your Android application, there are a few basic principles
you should follow. First, you should think in terms of screens when you plan the user interface. Model your
applications so that you have multiple screens, each focusing on a small set of actions that the user can
perform. For instance, a typical newsreader application would have one screen for listing news items, one for
adding news sources, one for reading news, and probably one for searching.
When defining the different screens you don’t need to focus on the details of the user interface. Simply try to
figure out what kind of information you want to display on each screen and leave the details about how to
display them for later.
Navigation
Once you have the different screens figured out you should start to think about how navigation works between
them. The navigation should be simple and straightforward so that the user will never be lost. Android provides
a number of navigational concepts that makes this process easier. When you start designing the navigational
structure you might also add additional screens to your application as needed.
Navigation in Android applications can be divided into four different categories: temporal, ancestral,
descendant, and lateral.
Temporal navigation is usually done with the Android back button, moving to the previous screen. This
navigation is usually handled automatically by the Android framework and doesn’t require any special code
by a developer. However, there can be situations where you wish to override the default handling of the back
button. For instance, when embedding a WebView for displaying web pages, you might wish to use the back
button in Android as a back navigation for the web pages.
Ancestral navigation refers to the navigation where the user moves up through the hierarchy to a parent screen, like
moving back to the start screen for the application. Ancestral navigation is solved in Android 4.1 and later through
the use of the android:parentActivityName attribute for each Activity in the application manifest.
For earlier versions of Android you need to use the Android support library together with a meta-data tag (see
http://developer.android.com/training/implementing-navigation/ancestral.html).
Descendant navigation is when the user navigates down through a hierarchy, for instance clicking on an item in
a list. Descendant navigation is the most common form in Android applications. It is typically handled through a
combination of Fragments and Activity instances where the user triggers actions that change the screen.
This kind of navigation will usually move down through the information hierarchy, but can also be used to
display additional information about the current object.
Lateral navigation is when the user moves to a sibling screen, for instance moving from one tab to another
sideways. This type of navigation is useful when your application will contain multiple lists of similar types,
but divided into different categories. One of the most common examples of this is the list of different types of
applications in the Google Play Store application.
Prototyping User Interfaces
When you get your screens and navigation completed, you can start prototyping the user interfaces. The
best way to start prototyping is with a paper and pencil. It is cheap, fast, and since users will interact with the

80 Part II: Getting the Most Out of Components
application using their fingers, it is easy to get a feel for how easy it is to use. Make a paper sketch for each
screen and add notes to clarify the UI. You can now “navigate” between your prototype screens in a way that’s
similar to how a real user would navigate in your application on a real device.
The paper prototype can start out simple with very little detail and evolve into a complete sketch of what the
user interface will look like. The important thing is to try several designs and not just stick to the first that comes
to mind. You should compare all your sketches to each other to find the best approach for each screen.
Once you feel you’ve got a good paper prototype, you can move on to create a more advanced prototype of the
user interface using Android Studio, as described in the next section.
Android Studio UI Designer
One of the best UI prototyping tools for Android applications is probably something that you’ve already
installed. Android Studio comes with a great UI designer toolkit that lets you work directly with XML layouts for
different screen sizes (see Figure 4-1). You can easily create a quick mockup that you can try out on your device
or an emulator.
Figure 4-1 Android Studio as a UI prototyping tool
Chapter 4: Android User Experience and Interface Design 81
One advantage with Android Studio UI designer is the tight integration with your code. You can easily switch
between different screen sizes, locale settings, and screen orientations and see the result immediately on the
screen.
By using Android Studio and its UI Designer tool you can create a working mockup of your user interface that
you can try out on a real device. You might have to add a minimal amount of code to fill the mockup with fake
data, but with only minor effort you can have a working mockup of your application in no time.
Android UI Elements
When developing Android applications you have a large set of ready-made UI elements, called widgets, in the
Android SDK that you can use. These widgets can be found in the android.widget package of the Android
APIs. You should try to use the existing widgets as much as possible. However, if your View hierarchy gets very
complicated you should consider creating a custom View, as described in Chapter 5, instead.
The main reason why you should use existing widgets as much as possible is because they are easily
recognizable by the user. In many cases, you want to create an application that will be distributed on multiple
platforms. When doing so, it can be tempting to re-use the same user interface design for all platforms. While
the concept of designing once and running the app “everywhere” might seem tempting at first, you will likely
create inconsistent user experiences that will have a very negative impact and alienate users.
This is also the reason why you should avoid creating your own look and feel for existing widgets. A user can
become confused if buttons suddenly change their appearance when they start your application. This concept
of “Pure Android” is described in further detail here: http://developer.android.com/design/
Text in Android Applications
One of the most important aspects of any application is the text. While placement of UI components are
important, it is the text together with images that is used to relay information to the user. Badly written text, the
wrong font or a text size that is too small can lead to an overall bad user experience.
Also, how you express your message in text matters, which is described in detail in the Writing Style section
found here: http://developer.android.com/design/style/writing.html.
Font Matters
There’s been a lot of debate over the years about fonts, particularly about whether using serif or sans serif is
better, even though studies have shown that neither appreciably affects how easy or fast people can read text.
What does matter is how easily a font can be recognized. The human brain uses pattern recognition to identify
letters in a text, so logic says that you should use an easily recognizable font. So, limit your use of highly
decorative fonts and use them only for logos and such.


82 Part II: Getting the Most Out of Components
Google has designed a default font for Android called Roboto (see Figure 4-2), which I recommend you use
unless you have a well-designed font that is part of your brand. This font was designed with all the modern
aspects of Android devices in mind, such as high-resolution screens.
Figure 4-2 Example of the Roboto font for Android
Text Layout
Another interesting aspect of readability is the fact that people read faster when lines are long but they prefer
to read short lines, which is one reason newspapers often use narrow columns for articles. So, consider what’s
of the most importance in the text you present. Use longer lines only if reading speed is important, although
text in applications is usually short, so this shouldn’t be much of a problem. The point is to keep lines of text
between 45 and 72 characters.
Length is less of a concern when you’re writing applications that will run on phones in portrait mode. The lines
will rarely be too long in those cases. However, when building applications for tablets or for landscape mode on
smartphones, keep this issue in mind. When the UI is wide, try to limit text to columns with between 45 to 72
characters within a given line. Figure 4-3 shows two examples of using long and short text lines.
Figure 4-3 Two layouts showing the differences between long and short text lines
Dimensions and Sizes
If you’ve already written Android applications, you know that you’re supposed to specify the sizes of your UI
elements using the dp (density-independent pixel) unit. The basic reason is to allow an Android application
to scale across different screen sizes, resolutions, and pixel densities without losing quality. When using dp,
the goal is to draw a View so that it has the same physical size on all screens. One dp is roughly equal to one
physical pixel on a 160 dpi screen.
You should specify all dimensions in your UI using the dp unit, with one exception: When specifying font sizes,
use the unit sp, which is based on the dp unit but also scaled according to the users’ preferences for font sizes.
Thus, by using sp for fonts, you can be sure that the text is printed with the size chosen by the user.


Chapter 4: Android User Experience and Interface Design 83
The other dimension units supported by Android are pt (points), px (pixel), mm (millimeter), and in
(inches). You should use these only in very specific cases and, as far as possible, provide all the default
sizes in dp or sp.
Recommended Dimensions
How large does a button need to be in an Android application? How much margin and padding do I need to
apply? How big should my icons be? If not for the dp unit, this question would have a very complicated answer.
The short answer is “the 48-dp rhythm.” Basically, 48 dp translates to about 9 mm on the screen, which is within
the suitable range for objects on a touchscreen that users need to interact with using their fingers.
This doesn’t mean that everything should be 48 dp, but that the UI components the user will interact with
should be at least that size. If a UI component needs to be larger than 48 dp, try to make it an even multiplier
com/design/style/metrics-grids.html.)
Figure 4-4 An illustration of the 48 dp rhythm for UI objects on Android
Icon Sizes
Outside the world of Android, the dp unit doesn’t exist, and you have to create a version of each icon for every
resolution you need to support. Android Studio will help you create the launcher icon for your application, and
you can use these sizes as a template for the other icons in your application. The resolutions you need are 48
pixels for MDPI, 72 pixels for HDPI, 96 pixels for XHDPI, and 144 pixels for XXHDPI—this is called the 2:3:4:6 ratio,
and you can use it as a guideline for other pixel sizes as well. You can see an example of the relative icon sizes in
Figure 4-5 (from http://developer.android.com/design/style/iconography.html).
Figure 4-5: The relative sizes of icons in Android for different screen sizes
84 Part II: Getting the Most Out of Components
When you display a bitmap as an icon in Android, don’t use px as the size for the View. Instead, use dp. A regular
icon, like the launcher icon on the Home screen, should be 48 dp by 48 dp, whereas icons in the action bar should
be 32 dp by 32 dp. Icons in the notification bar should be 24 dp by 24 dp. Smaller icons should use the size 16 dp
by 16 dp. Avoid icon sizes below 16 dp because some users may have trouble distinguishing them.
Text Size
Google created the font Roboto, which is used in all the standard Android applications. Although you can use a
different font in your application, using Roboto is recommended in order to be consistent with the standard UI
paradigm.
The size of a font is very important when it comes to ease of reading. Figure 4-6 shows how the size of a font is
measured. Different fonts with the same point size can seem to have different visual sizes. This comes from the
measurement called x-height, which is literally the size of the lowercase letter x in the font. A large X-height
makes a font look bigger and is easier to read. Other fonts that have large X-heights that we commonly use are
Arial and Verdana.
Figure 4-6 An illustration with the Roboto font showing how a
font size is measured
Google has also defined four standard font sizes for Android. These are micro (12 sp), small (14 sp), medium
(18 sp), and large (22 sp). By using the same size in your application, you’ll stay consistent with the rest of the
Android framework. Note that the sizes should be in the unit sp, not dp, to allow users to apply the scaling
factor they prefer in the Settings application.
Colors
I am actually the last person who should write about colors, given that I’m severely colorblind and need my wife
to help me whenever I buy clothes. Choosing colors for a UI is very difficult for people with normal color sight,
and being colorblind makes things even more complicated. Luckily, there are some general guidelines that even
I can understand and follow.
First of all, black and white are great colors. They have very good contrast, especially on the screens of Android
devices. If you’re uncertain about which colors to choose, start with these two and add other colors later only to
emphasize certain details.
When it comes to the color to use for text and its background, there are some governing rules. The LCD screens
usually found on Android devices are very different from paper. First, they emit light, which can cause eye strain
and make reading for a long time more difficult. Second, because the screen is refreshed continuously, the
image on the screen is not stable, even if the device is still. The refresh rate for most LCD screens is usually 60 Hz,
but some devices have a higher frequency.
Chapter 4: Android User Experience and Interface Design 85
Studies have shown that when reading text on a LCD screen, you should have as much contrast between the
text and the background as possible. This is why black and white are great colors to use when displaying text.
The best choice is to use black for the text color and white as the background—the opposite has proven to be
harder to read (see Figure 4-7).
Figure 4-7 An example of how contrast affects readability .
How the user may interpret a color is another reason to avoid using too many colors in your application. Colors
have different cultural meanings all over the world. For instance, the color green represents luck in Western
Europe, North America, and many Muslim countries, whereas Africa, Eastern Europe, and China use the color
red instead. Picking the wrong color could affect a significant part of your user-base in a negative way. A great
resource for interpreting what different colors mean in different cultures is the color wheel by David McCandles,
which you can find at http://www.informationisbeautiful.net/visualizations/colours-
Google recommends that you use primary colors for emphasis. The Android Design Guidelines (see http://
developer.android.com/design/style/color.html) contain a number of standard color swatches to use in your application. Pick the color scheme that matches your brand.
Color Blindness
There are different types of color blindness, and in most cases they all refer to an inability to distinguish
the difference between certain colors. The most common type of color blindness involves the inability to
distinguish between red and green, which can actually be difficult to do even when you’re not color blind.
About 9% of the male population and 1% of the female population are color blind.
A great tool for checking how your image looks to someone who is color blind is Vischeck, which you can find at
http://www.vischeck.com. This tool also lets you correct an image with regard to color blindness.
Images and Icons
All applications will contain at least one image; the image used as the launcher icon for your application. Your
application will most likely contain many other icons and images as well, and the way you design these can
have a big impact on how users perceive your application.
86 Part II: Getting the Most Out of Components
An icon consisting of many different and complex objects can have a negative impact on the perception of your
application. You should carefully design the launcher icon for your application so that it is easily recognized and
can be shown on both light and dark backgrounds, as you cannot be sure what kind of background the user will
have on her device.
Canonical Perspective
When told to draw an object from memory, most people will draw it as though looking at it from above at a
slight angle. This is called the canonical perspective, and it is also how we remember objects. For example, take a
piece of paper and draw a cup. Chances are it will look very much like Figure 4-8.
Figure 4-8 A teacup drawn from the canonical perspective
If you’re going to provide an icon of a real-world object, do users a big favor by designing it from a canonical
perspective; they’ll be able to quickly recognize and match the icon to the real-world object it represents.
Geons
Another interesting thing about objects is how we construct them in our memory. Studies have shown that we
are able to recognize objects by separating them into their component parts, or geons, and then using those
parts to build up more complex shapes. In Figure 4-9, you can see some geons and how our memories can
reconstruct them as real-world objects.
Chapter 4: Android User Experience and Interface Design 87
Figure 4-9 Objects and the geons they are constructed of
When you design an icon for your application, it is a good idea to construct it from simple geometric figures,
and keep in mind that the fewer geons you use for your icon, the faster the user will recognize what it
represents.
Recognizing Faces
As humans, we are very good at recognizing faces. Most people can easily pick out a friend’s face in a
crowd of people. We are actually faster at recognizing faces than other objects. Also, we are much slower at
understanding text that we read than recognizing a person’s face. By using this knowledge you can greatly
improve the user interface of your application.
If your application will integrate with a social network such as Twitter or Facebook, use this to your advantage.
Instead of having a long list of names with all the user’s friends, show a grid of profile photos. This way you can
fit more information on the screen at once, while making it easier to find the person the user is looking for.
Usability
According to Steve Krug in his book Don’t Make Me Think, the first law of usability is simply that: “Don’t make
me think!” A user shouldn’t have to spend a significant amount of time trying to figure out how to use your
application. Steve argues that users seeing your application’s UI for the first time shouldn’t have to question
what to do next; rather, the next step should be obvious.
88 Part II: Getting the Most Out of Components
This principle applies from overall UI navigation all the way down to single UI components. For example, users
can immediately recognize standard buttons; on the other hand, buttons with unfamiliar designs will require
conscious processing. Although you may favor a particular design over the standard button in Android, your
best bet is to use the standard button—because that’s what users will expect to see on their devices.
So, it’s important to follow the Android design principles. Of course, you can provide your own unique look
and feel to the user interface, but if you do so, make sure that you still provide a user-friendly interface that is
obvious to any user. Basically, break the rules only if you know how to break them effectively.
Visual Cues
In order to make your application user friendly, you should consider the visual cues of the UI elements that a
user will interact with. Visual cues are the “message” that an object signals to a user about how it is supposed to
be interacted with. A visual cue that is hard to understand, because it is unclear or complicated, might cause the
user to make mistakes or use the object in the wrong way.
An Android application is full of visual cues. The Home and Back buttons on Android devices are easily
recognizable and have clear visual cues on what they do and how to use them. The same goes for many of the
common actions, like the “share” action which is built-in in many Android applications.
Because people understand text slower than they understand a simple icon, you can make things much easier
for the user by providing a suitable icon for all buttons in your application. If your buttons will only contain text,
the visual cue that signals the action the button represents is harder to interpret and will require more time for
the user to understand.
For instance, consider a typical file browser application. When listing files, you provide two buttons, Send and
Delete. If the buttons will only contain text, it is much easier for the user to press the wrong button by mistake
than it would be if you also added an icon to each button. If you can’t fit both an icon and text, you should first
provide an icon.
The Android Design site contains a set of freely available icons that you can use in your application. You can find
these icons here: http://developer.android.com/design/style/iconography.html. By using these you will provide the same easily recognizable icons that many other applications use. This will reduce the
time required for a user to understand your application, as well as minimize the risk of a user performing the
wrong action.
Rewarding the User
Whatever the purpose of your application, the user will expect some sort of outcome. You can consider the
outcome as a kind of reward for the work they perform. Studies in this area have given us a number of tools that
we can apply when designing an application. In the world of Internet-connected apps and websites, the term
gamification has emerged as a way of describing how to apply rewards in an efficient way.
Chapter 4: Android User Experience and Interface Design 89
Gamification
The term gamification was coined in 2002 by a British computer programmer named Nick Pelling, but although
it was applied successfully at the time, the term didn’t gain popularity until around 2010.
The theory behind gamification is that game elements and mechanics outside the world of games (real-world
or computer-based) can improve the user’s engagement. People will naturally strive to compete, reach new
achievements, and achieve higher status. For example, when users are rewarded for using your application
frequently, they will feel and become more deeply engaged. If you provide some sort of immediate satisfaction
reward for every task completed, the users will respond at a faster rate than they would have without this
element of gamification. If you also introduce a concept of competing with other users, such as a high-score list
showing the “best players,” you can further increase their engagement. This in turn improves learning, increases
usage (and thus the profit), and provides you with more data for further improvements. When applied to
websites or applications, gamification can be a very powerful tool.
One of the best-known examples of gamification in the world of mobile applications is Foursquare, the location-
based social network service that lets users “check in” to locations. Foursquare badges are awarded to users
when they check in to new locations, when they have frequently checked in to the same location over a period
of time or when they manage to score the most number of check ins for a certain location. The result is that
Foursquare gained an immense database of places of interest around the world. The use of the application
shows Foursquare the places that are of most interest and how people move between these venues. This data
can then be licensed to third-party services that want to provide information about relevant locations.
Virtually any application can use gamification to increase the use and engagement of its users. I once used the
example of a notebook application for this purpose. If you want users to use your notebook application as much
as possible, you can introduce the achievements that are rewarded after they’ve written a certain number of
words, notes, or pages (see Figure 4-10). If you also provide a public high-score list that the users can see, you
will further improve the engagement.
Using a gamification element in your application can certainly drive user engagement and quickly increase your
user base. However, there are also risks involved. If it gets too easy, people will stop using it because there’s no
challenge. If it’s too hard, you’ll lose users who simply give up. Also, you have to be aware that some users might
turn to cheating, and if it’s easy to cheat, you’ll end up with a ruined game element.
Avoid building the entire user experience around the game element. For instance, Foursquare lets users
compete according to the amount of times they check in to a certain place and how many places they visit, but
the app also provides a very good set of features for finding points of interest and giving reviews.
You can also use the element of gamification to teach the user how to use your application. This can be
especially useful if you have a complicated app that requires some training.

90 Part II: Getting the Most Out of Components
Figure 4-10 An example of adding gamification elements
to a notebook application
Summary
In this chapter, I focused on the theory behind some of the concepts of interface design. You can learn much
more about this topic than I could ever cover by going through all the guidelines and tips on the Android
Design site. Also, I strongly recommend the books and other references found in the upcoming “Further
Resources” section.
Being a great developer doesn’t automatically mean that you’re also a great UI designer. But by understanding
the basics of how and why people react as they do to your user interface, you can avoid most design pitfalls.
That said, nothing beats a good professional interaction and UI designer. If possible, make sure that you have
one on your team and that she has an understanding of the Android Design guidelines.
Chapter 4: Android User Experience and Interface Design 91
Further Resources
Books
Weinschenk, Susan M., Ph.D. 100 Things Every Designer Needs to Know About People. New Riders, 2012.
Krug, Steve. Don’t Make Me Think: A Common Sense Approach to Web Usability, 2nd Edition . New Riders, 2005.
Lehtimäki, Juhani. Juhani Lehtimäki. Smashing Android UI. Wiley, 2012
Websites
Android Design at http://developer.android.com/design/index.html
The Easy Way to Writing Good User Stories at http://codesqueeze.com/the-easy-way-to-
Susan M. Weinschenks blog on how people think and behave: http://www.blog.theteamw.com
The Android Developers YouTube channel, specifically the Android Design in Action episodes: http://
www.youtube.com/user/androiddevelopers
Chapter 5
Android User Interface
Operations
In Chapter 4, I discuss how to design a good user interface, but that’s only half the work. Equally important
is knowing how to implement the interface using the Android APIs. Although the tutorials and guidelines
available on the Android Developers site are useful for more general cases, writing custom Views or detecting
advanced multi-touch gestures that aren’t directly available from the standard APIs is more complicated.
This chapter begins with a brief discussion about the Activity component and Fragments, followed by an
explanation of how you can use the new Presentation API to display a UI on a secondary screen.
Activities and Fragments are central to the user interfaces on Android. However, I cover them only very
briefly because they are covered to a great extent on the Android developer site and in other tutorials. Also,
because they’re such a crucial component for Android applications, I assume that most readers are familiar
with them.
Then comes an overview of how the View system works on Android, including the crucial issues involved in
implementing a custom View and how to manage the drawing across different screen sizes.
Next, I explain how to implement advanced multi-touch features in your application. Android has built-in
support for some multi-touch gestures, but for more advanced situations you need to build your own gesture
detection components.
Activities and Fragments
If you’re familiar with the lifecycle diagram for the Activity and Fragment classes shown in Figure 5-1, you
probably won’t have any problems with this part of Android UI. What is important with the lifecycles shown
in these diagrams is that you should try to perform cleanup operations (stopping and unbinding a Service,
closing connections etc.) in the callback method that matches the callback method where you performed the
initialization. For instance, if you bind to a Service in Activity.onResume(), you should always perform
the unbind operation in Activity.onPause(). This way, you reduce the chance that your application will
leak resources accidentally.
You’ll find Fragments beneficial when you need to reuse a part of your UI for different screen sizes. You aren’t
required to use Fragments, but doing so is recommended if your application will have one UI for handsets
and another UI for tablets.
94 Part II: Getting the Most Out of Components
Figure 5-1 The lifecycle diagrams for Activity and Fragment
Android Studio provides a great template for building a master/detail flow UI. This UI presents two Fragments
side by side on tablets (see Figure 5-2) and uses two separate Activities on handsets with smaller screens.
I recommend using this UI when you need to build an Android application that must support multiple screen
sizes in the same Android application package file (APK).

Chapter 5: Android User Interface Operations 95
Figure 5-2 The Master/Detail Flow template set up in Android Studio
Using Multiple Screens
With the release of Android 4.2 came the ability to use multiple screens to display a UI from an Activity. This
action is managed through the Presentation API that enables you to enumerate the available Displays and
assign a separate View to each.
Android defines a secondary screen as an abstract Presentation output where you add a View. The actual
physical display could be something connected by HDMI or a wireless display like a Miracast receiver. As a
developer, you don’t need to be concerned about the different types of displays, and you can work easily using
the Display class.
The following example shows how to use the DisplayManager to enumerate all the available Displays:
public class SecondDisplayDemo extends Activity {
private Presentation mPresentation;
@Override
protected void onCreate(Bundle savedInstanceState) {
96 Part II: Getting the Most Out of Components
super.onCreate(savedInstanceState);
setContentView(R.layout.device_screen);
}
@Override
protected void onResume() {
super.onResume();
setupSecondDisplay();
}
@Override
protected void onPause() {
super.onPause();
if (mPresentation != null) {
mPresentation.cancel();
}
}
private void setupSecondDisplay() {
DisplayManager displayManager = (DisplayManager)
getSystemService(Context.DISPLAY_SERVICE);
Display defaultDisplay = displayManager.
getDisplay(Display.DEFAULT_DISPLAY);
Display[] presentationDisplays = displayManager.
getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
if (presentationDisplays.length > 0) {
for (Display presentationDisplay : presentationDisplays) {
if (presentationDisplay.getDisplayId()
!= defaultDisplay.getDisplayId()) {
Presentation presentation =
new MyPresentation(this, presentationDisplay);
presentation.show();
mPresentation = presentation;
return;
}
}
}
Toast.makeText(this, “No second display found!”,
Toast.LENGTH_SHORT).show();
}
private class MyPresentation extends Presentation {
public MyPresentation(Context context, Display display) {
super(context, display);
// The View for the second screen
setContentView(R.layout.second_screen);
}
}
}
Chapter 5: Android User Interface Operations 97
In executing this example, you pick the first Display that isn’t the default (that is, the physical screen on the
device). You extend the Presentation class with your own implementation and add a different View as its
content view. The Presentation instance is bound to the same lifecycle as your Activity, so when the
user leaves the app, the default behavior for the second screen will kick in (usually cloning the default screen).
It may be a bit tricky to test the use of multiple screens during development, but you can find a developer
setting using the Settings➪Developer Options➪Simulate Secondary Displays commands. The simulated screen
appears where you can create a simulated display to use during development.
Designing Custom Views
Although the Android APIs provide a number of UI widgets that can be combined to form more complicated
components, sometimes it’s necessary to design your own custom View from scratch. Before you start
implementing a custom View there are a few details that you should be aware of, which I will explain next.
By following the example in this section, you’ll be constructing a custom View for a piano keyboard. This View
will display the keyboard and also play the right tone and change the look of the key when it’s pressed. Before I
show the code for this View, allow me to first take you through its lifecycle.
View Life Cycle
Just as a Fragment or an Activity has a lifecycle, so to do Views have their version of a lifecycle. This
cycle is not directly connected to the Fragment or Activity that displays the View; instead, the cycle is
connected to the state of the window it’s shown in and the rendering loop.
The first thing that happens when a View is added to the View hierarchy is that it gets a call to View.
onAttachedToWindow(), which signals to the View that it can now load things that it needs to work
properly. When building a custom View, you should override this method where you perform the loading of all
the resources and initiate any dependencies that the View needs. Basically, this is where you need to perform
any time-consuming initialization.
There is also a matching callback named View.onDetachedFromWindow(), which is called when the View
is removed from the View hierarchy. Here, you need to take care of all resources loaded, Services started, or
other dependencies that need explicit cleanup.
When the View is added to a View hierarchy, it will go through a loop where animations are calculated, followed
by View.onMeasure(), View.onLayout(), and finally View.onDraw(), as shown in Figure 5-3. The
system guarantees that these methods will be called in exactly that order every time.

98 Part II: Getting the Most Out of Components
View added
View.onAttachedToWindow()
Animate View
Rendering loop
View.onMeasure()
View.onLayout()
View.onDraw()
View removed
View.onAttachedToWindow()
Figure 5-3 A diagram of the View lifecycle
Piano Keyboard Widget
The View described in this section (see Figure 5-4) allows a user to tap a key that will then play a note. Everything
is managed by the View, so it needs to load all the audio clips for playback as well as manage the different states.
Finally, the user should be able to play with more than one finger, which requires properly using the multi-touch
features of the Android APIs.
Figure 5-4 A custom View showing a piano keyboard
The following is the first part of the new custom View:
public class PianoKeyboard extends View {
public static final String TAG = “PianoKeyboard”;
public static final int MAX_FINGERS = 5;
public static final int WHITE_KEYS_COUNT = 7;
public static final int BLACK_KEYS_COUNT = 5;
public static final float BLACK_TO_WHITE_WIDTH_RATIO = 0.625f;
public static final float BLACK_TO_WHITE_HEIGHT_RATIO = 0.54f;
private Paint mWhiteKeyPaint, mBlackKeyPaint,
Chapter 5: Android User Interface Operations 99
mBlackKeyHitPaint, mWhiteKeyHitPaint;
// Support up to five fingers
private Point[] mFingerPoints = new Point[MAX_FINGERS];
private int[] mFingerTones = new int[MAX_FINGERS];
private SoundPool mSoundPool;
private SparseIntArray mToneToIndexMap = new SparseIntArray();
private Paint mCKeyPaint, mCSharpKeyPaint, mDKeyPaint,
mDSharpKeyPaint, mEKeyPaint, mFKeyPaint,
mFSharpKeyPaint, mGKeyPaint, mGSharpKeyPaint,
mAKeyPaint, mASharpKeyPaint, mBKeyPaint;
private Rect mCKey = new Rect(), mCSharpKey = new Rect(),
mDKey = new Rect(), mDSharpKey = new Rect(),
mEKey = new Rect(), mFKey = new Rect(),
mFSharpKey = new Rect(), mGKey = new Rect(),
mGSharpKey = new Rect(), mAKey = new Rect(),
mASharpKey = new Rect(), mBKey = new Rect();
private MotionEvent.PointerCoords mPointerCoords;
public PianoKeyboard(Context context) {
super(context);
}
public PianoKeyboard(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PianoKeyboard(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mPointerCoords = new MotionEvent.PointerCoords();
Arrays.fill(mFingerPoints, null);
Arrays.fill(mFingerTones, -1);
loadKeySamples(getContext());
setupPaints();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
releaseKeySamples();
}
private void setupPaints() {
... omitted for brevity
}
private void loadKeySamples(Context context) {
mSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
100 Part II: Getting the Most Out of Components
mToneToIndexMap.put(R.raw.c, mSoundPool.load(context, R.raw.c,
1));
... omitted for brevity
}
public void releaseKeySamples() {
mToneToIndexMap.clear();
mSoundPool.release();
}
This code shows the member variables needed for the PianoKeyboard class as well as the constructors and
the attached/detached callbacks. Following this example, in onAttachedToWindows(), you reset the
member variables and load the audio clips. You create the different Paint objects, one for each possible state
for each key. The SoundPool is also populated with the audio clips stored in the raw resources.
Also, note that you create the Rect objects for each key as member variables with a default initialization.
Although you can create these objects on-the-fly in the onDraw() method, the method shown in the
preceding example will reduce the number of garbage collection (GC) calls which might impact the
performance negatively.
The next part is the onLayout() and onDraw() methods:
@Override
protected void onLayout(boolean changed, int left, int top,
int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// Calculate the sizes for the keys.
int width = getWidth();
int height = getHeight();
int whiteKeyWidth = width / WHITE_KEYS_COUNT;
int blackKeyWidth = (int) (whiteKeyWidth *
BLACK_TO_WHITE_WIDTH_RATIO);
int blackKeyHeight = (int) (height * BLACK_TO_WHITE_HEIGHT_RATIO);
// Define the rectangles for each key
mCKey.set(0, 0, whiteKeyWidth, height);
mCSharpKey.set(whiteKeyWidth - (blackKeyWidth / 2), 0,
whiteKeyWidth + (blackKeyWidth / 2), blackKeyHeight);
//... Remaining keys omitted for brevity
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Start by drawing the white keys
canvas.drawRect(mCKey, mCKeyPaint);
canvas.drawRect(mDKey, mDKeyPaint);
canvas.drawRect(mEKey, mEKeyPaint);
canvas.drawRect(mFKey, mFKeyPaint);
Chapter 5: Android User Interface Operations 101
canvas.drawRect(mGKey, mGKeyPaint);
canvas.drawRect(mAKey, mAKeyPaint);
canvas.drawRect(mBKey, mBKeyPaint);
// Draw black keys last since they will “cover” the white keys
canvas.drawRect(mCSharpKey, mCSharpKeyPaint);
canvas.drawRect(mDSharpKey, mDSharpKeyPaint);
canvas.drawRect(mFSharpKey, mFSharpKeyPaint);
canvas.drawRect(mGSharpKey, mGSharpKeyPaint);
canvas.drawRect(mASharpKey, mASharpKeyPaint);
}
In the onLayout() method, which is called during the layout pass, you calculate the size and position for
each key. In the onDraw() method you should avoid performing any heavy calculations and focus on the
actual drawing, which avoids potential drops in performance. Note: A custom onMeasure() method isn’t
implemented; that’s because the default measuring is sufficient in this case.
The final part is the onTouchEvent() callback that performs the actual playback of the audio clips and
changes the drawing state of the keys.
@Override
public boolean onTouchEvent(MotionEvent event) {
int pointerCount = event.getPointerCount();
int cappedPointerCount = pointerCount > MAX_FINGERS ?
MAX_FINGERS :
pointerCount;
int actionIndex = event.getActionIndex();
int action = event.getActionMasked();
int id = event.getPointerId(actionIndex);
// Check if we received a down or up action for a finger
if ((action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_DOWN) &&
id < MAX_FINGERS) {
mFingerPoints[id] = new Point((int) event.getX(actionIndex),
(int) event.getY(actionIndex));
} else if ((action == MotionEvent.ACTION_POINTER_UP ||
action == MotionEvent.ACTION_UP)
&& id < MAX_FINGERS) {
mFingerPoints[id] = null;
invalidateKey(mFingerTones[id]);
mFingerTones[id] = -1;
}
for (int i = 0; i < cappedPointerCount; i++) {
int index = event.findPointerIndex(i);
if (mFingerPoints[i] != null && index != -1) {
mFingerPoints[i].set((int) event.getX(index),
(int) event.getY(index));
int tone = getToneForPoint(mFingerPoints[i]);
if (tone != mFingerTones[i] && tone != -1) {
102 Part II: Getting the Most Out of Components
invalidateKey(mFingerTones[i]);
mFingerTones[i] = tone;
invalidateKey(mFingerTones[i]);
if (!isKeyDown(i)) {
int poolIndex =
mToneToIndexMap.get(mFingerTones[i]);
event.getPointerCoords(index, mPointerCoords);
float volume = mPointerCoords.
getAxisValue(MotionEvent.AXIS_PRESSURE);
volume = volume > 1f ? 1f : volume;
mSoundPool.play(poolIndex, volume, volume,
0, 0, 1f);
}
}
}
}
updatePaints();
return true;
}
// Check if the key touch by this finger is
// already pressed by another finger
private boolean isKeyDown(int finger) {
int key = getToneForPoint(mFingerPoints[finger]);
for (int i = 0; i < mFingerPoints.length; i++) {
if (i != finger) {
Point fingerPoint = mFingerPoints[i];
if (fingerPoint != null) {
int otherKey = getToneForPoint(fingerPoint);
if (otherKey == key) {
return true;
}
}
}
}
return false;
}
private void invalidateKey(int tone) {
switch (tone) {
case R.raw.c:
invalidate(mCKey);
break;
// Remaining cases omitted for brevity...
}
}
private void updatePaints() {
// Start by clearing all keys
Chapter 5: Android User Interface Operations 103
mCKeyPaint = mWhiteKeyPaint;
... remaining keys omitted for brevity
// Set “hit” paint on all keys touched by a finger
// starting with black keys
for (Point fingerPoint : mFingerPoints) {
if (fingerPoint != null) {
if (mCSharpKey.contains(fingerPoint.x, fingerPoint.y)) {
mCSharpKeyPaint = mBlackKeyHitPaint;
} else if (mDSharpKey.contains(fingerPoint.x,
fingerPoint.y)) {
... Remaining keys omitted for brevity
}
}
}
}
private int getToneForPoint(Point point) {
// Start by checking the black keys
if (mCSharpKey.contains(point.x, point.y))
return R.raw.c_sharp;
... remaining keys omitted for brevity
return -1;
}
}
For each MotionEvent, you check to see whether a new finger (pointer) has touched the screen. If so, you
create a new Point and store it in the array for tracking the user’s fingers. If an up event occurred, you remove
the Point for that finger instead.
Next, you go through all the pointers that are tracked by this MotionEvent and check whether they’ve moved
since the last call to this method. If so, you play the tone for the key currently being pressed. There is also a
check to ensure you don’t play a tone for a key that’s already being pressed when a second finger just moves
over the key.
Whenever a MotionEvent occurs, you also check which parts of the View need to be invalidated using
the invalidateKey() method. This check takes the ID for a key as a parameter and invalidates only that
rectangle. Whenever you need to invalidate your View in order to redraw it, call this method with only the
affected region. Doing so will significantly speed up the rendering of your View.
Multi-Touching
Ever since Android first achieved support for multi-touch technology, users have become accustomed to
doing some of the more advanced navigation in Android applications using two or more fingers. Most
prominent in this area is probably the Google Maps application. It combines most of the touch gestures—for
example, pinch-zoom, tilting, and rotating. Games requiring more than one finger for control is another area
in which multi-touch has become popular, and as shown in the PianoKeyboard example in the previous
section, multi-touch interaction is also useful in other areas.
104 Part II: Getting the Most Out of Components
The challenge when working with multi-touch is to keep track of the individual fingers. Android’s
MotionEvent class is the core for all pointer-related interactions, which means fingers, a stylus, a regular
computer mouse, or an external touchpad.
Take a look at another example for multi-touch. In this example, you create a custom View for finger painting.
You use the Path class from the android.graphics package to keep track of what the user’s fingers are
drawing. The same principle (that is, the methods involved in a custom View) that applied to the earlier piano
example is used here, but in this case there’s much less code to keep track of.
Specifically, the following code is a very simple example for creating a multi-touch–enabled finger painting
application.
public class PaintView extends View {
public static final int MAX_FINGERS = 5;
private Path[] mFingerPaths = new Path[MAX_FINGERS];
private Paint mFingerPaint;
private ArrayList<Path> mCompletedPaths;
private RectF mPathBounds = new RectF();
public PaintView(Context context) {
super(context);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public PaintView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mCompletedPaths = new ArrayList<Path>();
mFingerPaint = new Paint();
mFingerPaint.setAntiAlias(true);
mFingerPaint.setColor(Color.BLACK);
mFingerPaint.setStyle(Paint.Style.STROKE);
mFingerPaint.setStrokeWidth(6);
mFingerPaint.setStrokeCap(Paint.Cap.BUTT);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Path completedPath : mCompletedPaths) {
canvas.drawPath(completedPath, mFingerPaint);
}
for (Path fingerPath : mFingerPaths) {
Chapter 5: Android User Interface Operations 105
if (fingerPath != null) {
canvas.drawPath(fingerPath, mFingerPaint);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int pointerCount = event.getPointerCount();
int cappedPointerCount = pointerCount > MAX_FINGERS ?
MAX_FINGERS :
pointerCount;
int actionIndex = event.getActionIndex();
int action = event.getActionMasked();
int id = event.getPointerId(actionIndex);
if ((action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_POINTER_DOWN) &&
id < MAX_FINGERS) {
mFingerPaths[id] = new Path();
mFingerPaths[id].moveTo(event.getX(actionIndex),
event.getY(actionIndex));
} else if ((action == MotionEvent.ACTION_POINTER_UP ||
action == MotionEvent.ACTION_UP)
&& id < MAX_FINGERS) {
mFingerPaths[id].setLastPoint(event.getX(actionIndex),
event.getY(actionIndex));
mCompletedPaths.add(mFingerPaths[id]);
mFingerPaths[id].computeBounds(mPathBounds, true);
invalidate((int) mPathBounds.left, (int) mPathBounds.top,
(int) mPathBounds.right, (int) mPathBounds.bottom);
mFingerPaths[id] = null;
}
for(int i = 0; i < cappedPointerCount; i++) {
if(mFingerPaths[i] != null) {
int index = event.findPointerIndex(i);
mFingerPaths[i].lineTo(event.getX(index),
event.getY(index));
mFingerPaths[i].computeBounds(mPathBounds, true);
invalidate((int) mPathBounds.left, (int) mPathBounds.top,
(int) mPathBounds.right,
(int) mPathBounds.bottom);
}
}
return true;
}
}
Note how you use the Path class to add a new line for each new event. Although this class isn’t completely
accurate (you should check that a pointer has actually moved before adding a new line), it illustrates how to
create a more complex drawing application.
106 Part II: Getting the Most Out of Components
PointerCoordinates
Each MotionEvent contains all the information about each pointer. Because a pointer can be the result
of many different types of input devices (such as a finger, a stylus, or a mouse), it can also contain more
information than the x, y coordinates. The APIs in Android support all the input devices defined by the Linux
kernel. Because the parameters for an input can vary between devices, the design is such that each pointer has
a number of axes. The two most commonly used axes are the x, y coordinates for the pointer, but there is also
axis information for pressure, distance, and orientation. Also, because the MotionEvent class can be used
for inputs other than those for generating pointer coordinates, this class also has support for axis information
related to gaming controllers and other ways of doing input, such as throttle, rudder, tilt, or scroll wheel. Use
this class when you want to support external inputs such as game controllers.
The following code is a snippet from the previous PianoKeyboard example:
event.getPointerCoords(index, mPointerCoords);
float volume = mPointerCoords.getAxisValue(MotionEvent.AXIS_PRESSURE);
volume = volume > 1f ? 1f : volume;
mSoundPool.play(poolIndex, volume, volume, 0, 0, 1f);
This code shows how to populate a PointerCoords object with the data for a specific pointer. In this case,
you use the pressure axis to set the volume for the audio clip playback.
The pressure axis (AXIS_PRESSURE) in the preceding example is usually a virtual value that’s
calculated by determining the surface covered by a finger. Normally, the capacitive touchscreens on
modern smartphones don’t support a real touch pressure value.
Rotate Gesture
In the Android APIs, you can find two utility classes that help you detect a number of touch gestures: the
GestureDetector and ScaleGestureDetector classes. The first class supports a number of simple
single-touch gestures, such a long press, double tap, and fling. The second class provides a way to detect the
pinch-zoom gesture used in Google Maps and when zooming in on images. However, one gesture that lacks
support in the Android APIs is rotation.
The following class exemplifies how to implement a rotation gesture detector for a View. The relevant code is
marked in bold.
public class RotateView extends View {
public static final String TAG = “RotateView”;
private static final double MAX_ANGLE = 1e-1;
private Paint mPaint;
private float mRotation;
private Float mPreviousAngle;
public RotateView(Context context) {
super(context);
Chapter 5: Android User Interface Operations 107
}
public RotateView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RotateView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10);
mPaint.setAntiAlias(true);
mPreviousAngle = null;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
int radius = (int) (width > height ?
height * 0.666f : width * 0.666f) / 2;
canvas.drawCircle(width / 2, height / 2, radius, mPaint);
canvas.save();
canvas.rotate(mRotation, width / 2, height / 2);
canvas.drawLine(width / 2, height * 0.1f,
width / 2, height * 0.9f, mPaint);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getPointerCount() == 2) {
float currentAngle = (float) angle(event);
if(mPreviousAngle != null) {
mRotation -= Math.toDegrees(clamp(mPreviousAngle –
currentAngle,
-MAX_ANGLE, MAX_ANGLE));
invalidate();
}
mPreviousAngle = currentAngle;
} else {
mPreviousAngle = null;
108 Part II: Getting the Most Out of Components
}
return true;
}
private static double angle(MotionEvent event) {
double deltaX = (event.getX(0) - event.getX(1));
double deltaY = (event.getY(0) - event.getY(1));
return Math.atan2(deltaY, deltaX);
}
private static double clamp(double value, double min, double max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
}
The trick comes from using Math.atan2() to calculate the current angle. This method implements the two
argument arctangent function, which is used for calculating the angle between the positive x-axis on a plane
and the coordinates defined by the two parameters. Next, you subtract the previously calculated angle from
the current one and clamp the result between a maximum and a minimum for each event. Finally, because the
rotation operations on the Canvas use degrees, you convert the result using Math.toDegrees().
OpenGL ES
Although most Android applications can be built using the widgets provided by the SDK or through a custom
View, at times you may need a more low-level and high-performance API for graphics, most often for games.
The API you will use in this case is OpenGL ES (Embedded Subsystem) and Android supports all versions up
to 3.0 (depending on the hardware and Android version). The latest OpenGL ES standard, version 3.0, was
added to Android version 4.3. This is the first mobile platform to support OpenGL ES, and it’s expected to allow
developers to create more advanced graphics for their games.
Android is already using OpenGL ES 2.0 for its standard UI framework to enable hardware-accelerated graphics,
but it’s hidden from developers. In this section, I introduce you to OpenGL ES 2.0 and 3.0. The 3.0 version is fully
backward-compatible with 2.0, so you can build applications that do a graceful degradation to version 2.0 if the
device doesn’t support the later API.
For an introduction to OpenGL ES on Android, I recommend the guide from the Android Developers site
(http://developer.android.com/guide/topics/graphics/opengl.html). However, when you need to use OpenGL ES in your application or game, you will most likely not write all the OpenGL ES code
described in this guide. Instead, you should use a scene graph framework or game engine, which hides most of
the complex details involved with OpenGL ES in an easy-to-use API.
Chapter 5: Android User Interface Operations 109
Scene Graphs and Graphics Engines
The easiest way to work with OpenGL ES is to use a scene graph, which is basically a graph where each node
contains information about something being rendered in your scene. You could write your own scene graph,
but using one of the many that exist online is usually better. Some of the different options are free and open
source licensed and some are commercial. Scene graphs are also called 3D, graphics, or game engines because
they also contain functionality specific for advanced graphics and games.
One of the better and most active open source 3D engines is Rajawali, developed by Dennis Ippel. You can
find all of the information, including a number of great tutorials, for Rajawali at https://github.com/
One of the better commercial alternatives you can find is Unity3D from Unity Technology. This is much more
than a game engine and contains a complete development studio for game developers. You can find more
information about Unity3D at http://unity3d.com.
Always consider the needs of your application or game before you pick a 3D engine because changing it later
can be very difficult. One of the most important things to consider is whether you want to be able to easily port
your game to a different platform (for instance, iOS). In that case, choose one that supports all the platforms you
intend to target (Unity3D has very good multi-platform support).
Summary
With the advanced UI operations covered in this chapter, you have a set of tools that can help you enhance your
application’s performance. For example, perhaps your app would benefit by supporting a secondary screen
using HDMI or Miracast, which is when the new Presentation API will be useful.
Eventually, all Android developers create custom View classes for their applications. When you do so, be sure to
follow the lifecycle for a View and use the different callbacks correctly.
When you need to support advanced multi-touch interactions, you must distinguish between different pointers
and track them individually. As I’ve shown in this chapter, all MotionEvents contain the current information
about all the pointers.
When you create advanced and high-performance graphics, you’ll probably need to use OpenGL ES. At the
very least, use OpenGL ES 2.0; and for even more advanced graphics, consider using OpenGL ES 3.0 when it
is available on the user’s device. Also, I strongly recommend utilizing a complete 3D or game engine when
developing games; doing so will make your work much easier.
The Android UI is probably the biggest single area of the entire platform. You can find numerous tutorials,
guidelines, samples, and books online on this topic; I mention some of my favorites in the following “Further
Resources” section. The important thing to remember when you implement your UI is to stick with what you can
manage.
110 Part II: Getting the Most Out of Components
Further Resources
Books
Lehtimäki, Juhani. Smashing Android UI. Wiley, 2012.
Websites
The OpenGL ES guide from the Android Developers site: http://developer.android.com/guide/
Training on working with the Fragments API: http://developer.android.com/training/
How to write a custom View: https://developers.google.com/events/io/
Chapter 6
Services and
Background Tasks
An important part of any Android application is making sure that long-running and blocking operations are
executed in the background so that the main thread is left alone as much as possible. Although you can simply
start a new thread in your Activities, a better approach is to move many of the background operations to
a separate Service. The Service component in Android provides an efficient way of separating application
logic for background tasks from the code that handles the user interface.
In this chapter, I cover the use of a Service component when performing background operations. I start
with explaining when it’s appropriate to use a Service and how to design and configure the component
in an optimal way. I also give a detailed description of the lifecycles that a Service runs through. I explain
communication with a Service from the other components in detail and finish this chapter with some best
practices for how to move the work on a Service to a background thread.
When and How to Use a Service
The Android documentation for Service components starts by describing a Service as follows (I suggest
keeping this in mind when developing your Android application):
A Service is an application component representing either an application’s desire to perform a
longer-running operation while not interacting with the user or to supply functionality for other
applications to use.
In this chapter, I focus on performing long-running operations and cover the second part of the quotation in
Chapter 7, where I describe how to communicate between two applications.
Because all Android components are running on the main thread of the application process, it might seem
unnecessary to use a Service as you still need to use some thread mechanism to move the operation off
the main thread. The reason for using a Service is based on the difference in how the lifecycle works in
Services and in Activities. I go into the details of the Service lifecycle in the section “Understanding
the Service Lifecycle” later in this chapter, but basically, the Service is better adapted to act as the component
for managing long-running operations in Android than an Activity.
Other questions to consider: Should an operation be long-running? When should you move an operation to a
background thread? Is it ever okay to use a background thread like an AsyncTask from within the Activity,
instead of moving it to a Service?
112 Part II: Getting the Most Out of Components
I recommend moving any operation that doesn’t focus on the user interface to a background thread and
making sure that this thread is started and controlled by a Service. That said, I tend to bend that rule
depending on the situation. For instance, I always, with no exception, perform network operations from a
Service. However, it’s usually okay to write data to local storage, such as a content provider or a preferences
file, within the Activity if the data being written is also generated from the user interface, as in editing a
contact’s information.
Another example is when you’re playing audio in your app. A Service typically controls a music player’s
MediaPlayer or AudioTrack object, whereas an Activity handles the sound effects in games and
applications. If in doubt, it is usually safe to move the operation to a background thread in a Service.
Service Types
I like to divide Services into two different types. First is the one that performs work for the application
independent of the user’s input. For instance, a music player is able to play music, even if the user doesn’t have
the app in the foreground. When playback of the current track is complete, a Service in the music player app
starts playing the next track in the playlist. Another example is a messaging application that needs to receive
incoming messages at all times and needs to remain running until the user explicitly logs out.
The other type of Service is one that’s directly triggered by an action from the user—for example, a photo-
sharing application. The user takes a photo, and the application sends it (or rather, a Uri to the locally stored
photo) to a Service using an Intent. The Service starts, parses the data in the Intent, and spawns
a background thread that uploads the photo. When the operation is complete, the Service is stopped
automatically by the system.
Understanding the Service Lifecycle
Services in Android have a slightly different lifecycle than Activities do. First of all, the Service
lifecycle isn’t directly affected by user interactions. In an Activity, when the user taps the Home button, the
onPause() callback is always called. For a Service, no callbacks are directly triggered in the same way by
the user’s actions. Instead, there are only two callbacks that will always be called for a Service: onCreate()
and onDestroy().
(There are also other callbacks that may be called depending on the interaction with the Service or at system
and device changes such as, when the screen orientation changes from landscape to portrait mode.)
Simplified, a Service is either started or stopped, which makes it much easier to handle than the more
complicated lifecycle of an Activity. All you really need to remember is to create expensive objects in
onCreate() and do all cleanup in onDestroy().