Efficient Java Code for Android - Building a Better Foundation - Android Programming: Pushing the Limits (2014)

Android Programming: Pushing the Limits (2014)

Part I. Building a Better Foundation

Chapter 2. Efficient Java Code for Android

Today there are three versions of the Java platform, Java ME (Micro Edition, for certain mobile phones), Java SE

(Standard Edition, for desktops), and Java EE (Enterprise Edition, for server-side applications). When talking about Java

in general, I am usually referring to Java SE because this is the version that contains a virtual machine and a compiler.

Java code is compiled to an intermediate format called byte-code. This byte-code is then parsed by a virtual

machine on the target computer that can quickly translate it to the native format required for that particular

hardware and operating system.

Besides providing a “Write Once, Run Anywhere” advantage for developers, Java has automatic memory

management through a garbage collector (GC), reducing the need for you, as a developer, to de-allocate

memory from unused objects in your code. Although this feature is very useful and greatly reduces the risk of

introducing memory bugs in your code, because the garbage collection process needs to execute continuously,

it adds an overhead when running.

I start this chapter by doing a high-level comparison of the differences between Java SE and the Java used for

Android development. I focus on the Java SE language construct that you may be used to and how it works on

Android. Then I focus on how to optimize Java code for Android, how to optimize memory allocations, and how

to handle multithreading properly.

Comparing Android’s Dalvik Java to Java SE

Although developers were able to write applications for mobile devices using the Java programming language

long before Android, it was a severely limited version of Java called Java ME (Micro Edition). Java ME also

differed among different device manufacturers, making it almost impossible to write an application that would

work on any phone supporting Java ME. Also, the distribution of apps was very complicated because no well-

supported online stores existed at that time.

The launch of Android gave developers the option to build very capable applications for smartphones by

writing code using the Java programming language and using the same API they were used to in the standard

Java domain. However, although Android developers still use the compiler from Java SE to compile their

applications, you can find many differences between the Java that James Gosling developed and the way Java

works on your Android device.

The VM (virtual machine) that runs on an Android device is called Dalvik. It was originally developed by Dan

Bornstein at Google and provided a virtual machine suitable for CPU and memory-constrained devices. There

are several differences between Java SE and Dalvik Java, mostly regarding the virtual machine. Although Java

SE uses a stack machine design, Dalvik was designed as a register-based machine. The Android SDK has a tool

called dx that converts the Java SE stack machine byte-code to Dalvik register-based machine byte-code. The

conversion step is done automatically by your IDE so that you don’t need to bother about it.

The exact definition and technical difference between a stack-based machine and a register-based machine is

beyond the scope of this book. Android uses a register-based machine for historical reasons. Although a register-

based machine can be up to 32% faster than a stack-based machine, this is true only for virtual machines that are

interpreting the byte-code at execution (that is, interpreted virtual machines). Up until Android version 2.2 (also

known as Froyo), the Dalvik VM was purely interpreted. With the Froyo version of Android came the introduction of

a JIT compiler (Just In Time), something that Java SE had benefitted from for a long time.

JIT compilation, also known as dynamic translation, takes the byte-code and translates it into native code prior

to execution (see Figure 2-1), which has two major benefits. First, it eliminates much of the overhead associated

with pure interpreted VMs; second, it can perform optimizations to the native code that wouldn’t be possible

with statically compiled code. For instance, the JIT compiler may choose the most appropriate optimizations for

the CPU it is currently running. It’s also possible for a JIT compiler to analyze how the code is running to perform

further optimizations based on the application’s input.

Figure 2-1 Translation steps for Android Java and Java SE

As promising as this sounds, Android’s Dalvik JIT compiler has a long journey ahead before it reaches the same

level of maturity as the JIT compiler in Java SE. Still, the presence of a JIT in Dalvik provides great performance

benefits for Android, and it’s continuously being improved.

Another difference between the Java SE VM and the Dalvik VM is that the latter is optimized for running in

multiple instances on the same machine. This is handled by a process started at boot called zygote that creates

the first Dalvik instance that will be the parent of all other instances. Once an application starts, the zygote

process receives a request for a new VM instance and forks a new process that is assigned to the newly started

application, as shown in Figure 2-2. This design may seem impractical if you’re used to working with Java SE,

but it has a major advantage because it protects you from multiple application crashes in cases where one

application has a runtime failure that will crash the Dalvik VM.

Figure 2-2 Launching of new Dalvik VM instances in Android

In addition to running with a different virtual machine than the one Java SE uses, Android has a different

implementation of the APIs. All the APIs in Android that belong to the java or javax packages come from

Apache Harmony, an open-source project aiming for reimplementation of the Java SE stack. (The Apache Harmony

project has been retired since November 2011 and is no longer being actively developed.) In terms of developing,

these APIs are identical to the ones that are found in Java SE, but some differences do exist. (For instance, Google

has made major upgrades to the HttpUrlConnection class that is not present in the Java SE version.)

Also, not all of the Java SE APIs are available on Android because they’re irrelevant for this platform. For instance, the

Swing/AWT packages have been completely removed because Android uses a different UI framework. Other APIs

that have been removed are RMI, CORBA, ImageIO, and JMX. These have either been replaced by an Android specific

version (in the android package space) or simply don’t have an equivalent in Android for practical reasons.

Optimizing Java Code for Android

Java SE has evolved over the years with new features that simplify writing complicated code structures. Many

of the features make it easier for developers, and you need to understand when and how to use them properly.

Also, because Java SE has been used mostly for server-side development (using the Java Enterprise Edition

APIs), Java code has been optimized to meet server-side requirements. Annotations and support for scripting

languages in the Java SE virtual machine are examples of optimizations focused on server-side development.

Although powerful tools when building your back end, these kinds of features serve little purpose and can even

be fatal when writing client-side code as done in an Android application. Java developers have gotten used to

unlimited amounts of RAM and CPU, whereas Android development requires close attention to performance

and allocations. Simply put, you need a slightly different approach when writing code for Android as compared

to developing back end solutions in Java.

However, some recommendations have changed since Android was first released. Some modern Java

constructs once avoided on Android are now recommended, mostly because of the modern JIT compiler for

Android that removes many of the performance bottlenecks these constructs used to cause.

This section deals with the aspects of Java code that you need to understand when writing Android

applications. While the details of the Java programming language are outside the scope of this book; instead,

I focus on what is important for Android development. Still, it’s important to understand that most of the rules

and recommendations that apply to Java SE apply to Android and the Dalvik VM.

Type-Safe Enum on Android

With Java SE 5.0 came many new features in the Java programming language that made life easier for Java

developers. One of the most anticipated features was the introduction of type-safe enumerations. Enumerations

are used to represent a number of choices in code that belong to a common group. In earlier versions of Java,

multiple integer constants were used to solve this. Although this works technically, it suffers from being quite

error-prone. Take a look at the following code:

public class Machine {

public static final int STOPPED = 10;

public static final int INITIALIZING = 20;

public static final int STARTING = 30;

public static final int RUNNING = 40;

public static final int STOPPING = 50;

public static final int CRASHED = 60;

private int mState;

public Machine() {

mState = STOPPED;

}

public int getState() {

return mState;

}

public void setState(int state) {

mState = state;

}

}

The problem is that although the constants are the values you expect in the setter, nothing is preventing the

method setState() from receiving a different value. If you add a check in the setter, you need to handle the

error in case you get an unexpected value. What you want is a compile-time check that prevents you from ever

assigning an illegal value. Type-safe Java enum solves this problem, as shown here:

public class Machine {

public enum State {

STOPPED, INITIALIZING, STARTING, RUNNING, STOPPING, CRASHED

}

private State mState;

public Machine() {

mState = State.STOPPED;

}

public State getState() {

return mState;

}

public void setState(State state) {

mState = state;

}

}

Notice the new inner enum class added where you declare different states as type-safe values. This solves the

problem with unexpected values at compile time, so the code will be much less error-prone.

Before the Dalvik VM had a JIT compiler that optimized the code, using type-safe enum was discouraged on

Android because the memory and performance penalties associated with this design were greater than when

using integer constants. This is why so many integer constants are in the older parts of the Android APIs. These

days, with a capable JIT compiler and an ever-improving Dalvik VM, you don’t have to worry about that issue

and are encouraged to use type-safe enum in your application code.

However, there are still situations where integer constants are preferable. With basic types like the Java int, you

won’t increase the amount of work for the GC. Also, many existing APIs in the Android SDK still rely on basic

types as parameters—for example, the Handler class described in the “Multithreading on Android” section

later in this chapter—in these cases, you don’t have much choice.

Enhanced For-Loop on Android

Java SE 5.0 also introduced the enhanced for-loop that provides a generic an abbreviated expression for looping

over collections and arrays. First, compare the following five methods:

void loopOne(String[] names) {

int size = names.length;

for (int i = 0; i < size; i++) {

printName(names[i]);

}

}

void loopTwo(String[] names) {

for (String name : names) {

printName(name);

}

}

void loopThree(Collection<String> names) {

for (String name : names) {

printName(name);

}

}

void loopFour(Collection<String> names) {

Iterator<String> iterator = names.iterator();

while (iterator.hasNext()) {

printName(iterator.next());

}

}

// Avoid using enhanced for-loops for ArrayList

void loopFive(ArrayList<String> names) {

int size = names.size();

for (int i = 0; i < size; i++) {

printName(names.get(i));

}

}

These methods show four different ways of looping through collections and arrays. The first two methods have

the same performance, so it’s safe to use the enhanced for-loop on arrays if you’re just going to read the entries.

For Collection objects, you get the same performance when using the enhanced for-loop as when you

manually retrieve an Iterator for traversal. The only time you should do a manual for-loop is when you have

an ArrayList object.

In the cases where you not only need the value of each entry but also the position, be sure to use either an array

or an ArrayList because all other Collection classes are much slower in these situations.

In general, if you need high-quality performance when reading sets of data that rarely change, use a regular

array. However, arrays have a fixed size and will affect performance when adding data, so consider all factors

when writing your code.

Queues, Synchronization, and Locks

Frequently, an application will produce data in one thread and consume them in another. A common example

is when you’re reading data from the network on one thread and want to display the data to the user on a

different thread (the main thread where UI operations occur). This pattern is usually called the consumer/

producer pattern, and in their object-oriented programming courses, programmers may spend several hours

implementing this in their algorithm. In this section, I’ll show some of the ready-made classes that make it easier

to implement this behavior.

Smarter Queues

Many Java developers still choose to implement queues in their code using LinkedList and

synchronized blocks, although there are ready-made classes that do so and require much less code. You

can find the classes for performing concurrent programming in the java.util.concurrent package. In

addition, you can find classes for semaphores, locks, and atomic operations on single variables. Consider the

following code where a thread-safe queue using a standard LinkedList is implemented:

public class ThreadSafeQueue {

private LinkedList<String> mList = new LinkedList<String>();

private final Object mLock = new Object();

public void offer(String value) {

synchronized (mLock) {

mList.offer(value);

mLock.notifyAll();

}

}

public synchronized String poll() {

synchronized (mLock) {

while(mList.isEmpty()) {

try {

mLock.wait();

} catch (InterruptedException e) {

// Ignore for brevity

}

}

return mList.poll();

}

}

}

Although this code is correct and would probably merit a full score on an exam, it’s simply a waste of your time

to implement and test it. Instead, you can replace all the preceding code with the following line:

LinkedBlockingQueue<String> blockingQueue =

new LinkedBlockingQueue<String>();

This one line gives you the same type of blocking queue as the previous example and even provides additional

thread-safe operations. The java.util.concurrent package has a number of alternative queues and

deuce classes as well as concurrent map classes, so in general, I suggest using them rather than using lengthier

code similar to my earlier example.

Smarter Locks

The synchronized keyword in Java provides a powerful feature that allows you to make a method

or call-block thread safe. Although easy to use, it is also easy to apply it too widely, which can have very

negative impact on performance. When you need to differentiate between reading and writing data, the

synchronized keyword is not the most efficient. Luckily, a utility class in the java.util.concurrent.

locks package provides exactly that support.

public class ReadWriteLockDemo {

private final ReentrantReadWriteLock mLock;

private String mName;

private int mAge;

private String mAddress;

public ReadWriteLockDemo() {

mLock = new ReentrantReadWriteLock();

}

public void setPersonData(String name, int age, String address) {

ReentrantReadWriteLock.WriteLock writeLock = mLock.writeLock();

try {

writeLock.lock();

mName = name;

mAge = age;

mAddress = address;

} finally {

writeLock.unlock();

}

}

public String getName() {

ReentrantReadWriteLock.ReadLock readLock = mLock.readLock();

try {

readLock.lock();

return mName;

} finally {

readLock.unlock();

}

}

// Repeated for mAge and mAddress…

}

The preceding code exemplifies where to use a ReentrantReadWriteLock that allows read-only access

from multiple concurrent threads while making sure that only one thread at a time can write to the same data.

Using synchronized in your code is still a valid way of handling locks, but always consider whether a

ReentrantReadWriteLock could be a more efficient solution.

Memory Management and Allocations

The automatic memory management in Java has effectively eliminated many of the most common bugs in

software development. When you no longer have to remember to release every allocation of a new object in

your code, you save time that you can use to improve the features and overall quality of software.

But this feature doesn’t come for free because you now have an automatic garbage collector that runs in

parallel with your application. The GC will run continuously and check whether any memory allocations can be

reclaimed. This behavior means that the threads in your application will compete for CPU time with the GC, so

it’s crucial to make sure that GC calls don’t take too long whenever it is running.

Also, automatic memory management does not remove the possibility for memory leaks. If you keep references

to objects that are no longer needed, the GC will not collect them, and they will waste memory. If objects

are being allocated continuously but are never being released, you’ll eventually run into an OutOfMemory

exception, and your application will crash. So, try to avoid keeping references to objects in the main Android

components; otherwise, they may never be “garbage collected” during the application’s lifetime.

Reducing Object Allocations

On Java and Android, the most common problem with automatic memory management is when you are

allocating unnecessary objects that keep the GC working more than it should. Consider a case in which a simple

class represents a pair of integers:

public final class Pair {

public int firstValue;

public int secondValue;

public Pair(int firstValue, int secondValue) {

this.firstValue = firstValue;

this.secondValue = secondValue;

}

}

Now, say that you receive an array of integers in your application that you divide into pairs and then send to the

method sendPair. Here is an example of when memory allocation is done badly:

public void badObjectAllocationExample(int[] pairs) {

if(pairs.length % 2 != 0) {

throw new IllegalArgumentException(“Bad array size!”);

}

for(int i = 0; i < pairs.length; i+=2) {

Pair pair = new Pair(pairs[i], pairs[i+1]);

sendPair(pair);

}

}

Although this is a very crude example of how to generate Pair objects (and potentially cause a crash if the

length of the array is not an even size), it demonstrates a surprisingly common mistake: allocating objects

inside a loop. The GC will have a lot of work to do inside the previous loop above and will most likely cause the

application UI to stutter from CPU exhaustion. If you know that the sendPair method won’t keep a reference

to the Pair object after it returns, your solution is simply to move the creation of the Pair object outside the

loop and reuse the object, as shown as follows:

public void betterObjectAllocationExample(int[] pairs) {

if(pairs.length % 2 != 0) {

throw new IllegalArgumentException (“Bad array size!”);

}

Point thePair = new Point(0,0);

for (int i = 0; i < pairs.length; i+=2) {

thePair.set(pairs [i], pairs [i+1]);

sendPair(thePair);

}

}

In this new version of the method, you ensure that the object is reused during the entire run of the method.

There will be only one GC call once the method returns. Remember, when allocating objects, avoid doing so

inside a loop when possible.

Sometimes, however, you can’t avoid creating objects inside a loop, so you also need a way of handling those

situations. The solution here is to allocate objects on demand using a static factory method. (Joshua Bloch

describes this method in detail in Item 1 of his book Effective Java. )

This approach is commonly used in the Android framework and APIs and allows you to use a behind-the-scenes

object cache that is populated on demand. The only drawback is that you need to manually recycle the objects,

or the cache will always be empty.

Based on your previous example, you start by refactoring the Pair class so that you have a simple pool for

reusing objects.

public final class Pair {

public int firstValue;

public int secondValue;

// Reference to next object in the pool

private Pair next;

// The lock used for synchronization

private static final Object sPoolSync = new Object();

// The first available object in the pool

private static Pair sPool;

private static int sPoolSize = 0;

private static final int MAX_POOL_SIZE = 50;

/**

* Only allow new objects from obtain()

*/

private Pair() { }

/**

* Return recycled object or new if pool is empty

*/

public static Pair obtain() {

synchronized (sPoolSync) {

if (sPool != null) {

Pair m = sPool;

sPool = m.next;

m.next = null;

sPoolSize--;

return m;

}

}

return new Pair();

}

/**

* Recycle this object. You must release all references to

* this instance after calling this method.

*/

public void recycle() {

synchronized (sPoolSync) {

if (sPoolSize < MAX_POOL_SIZE) {

next = sPool;

sPool = this;

sPoolSize++;

}

}

}

}

Note that a number of fields are added, both static and non-static. You use these fields to implement a

traditional linked list of Pair objects. Objects of this class are created only through the obtain method.

You prevent new objects from outside this class by making the constructor private. The obtain method first

checks whether the pool contains any existing objects and removes the first element in the list and returns it. If

the pool is empty, it simply creates a new object. To put the object back into the pool, you call recycle once

you’re done. At that point, it is very important that you don’t touch that object again.

With this modification of the Pair class, your previous method with the loop also needs some changes.

public void bestObjectAllocationExample(int[] pairs) {

if(pairs.length % 2 != 0) throw new IllegalArgumentException (“Bad

array size!”);

for (int i = 0; i < pairs.length; i+=2) {

Pair pair = Pair.obtain();

pair.firstValue = pairs[i];

pair.secondValue = pairs[i+1];

sendPair(pair);

pair.recycle();

}

}

The first time this method runs, you create a new instance of Pair, which will then be reused for every new

iteration. However, the next time you run this method, no new object is created. Also, because the obtain

and recycle methods are thread-safe, this method is safe to execute in multiple concurrent threads. The only

drawback is that you have to remember to call recycle manually, but this is a small price to pay considering

you’ve postponed all GC calls for the Pair class until the application exits.

The example with the Pair class is very trivial, but it illustrates a pattern that is highly encouraging if you have

a class that would otherwise be created frequently in your code. This design may look familiar because it’s in

several places in the Android source code and APIs. Commonly used classes such as Message, MotionEvent,

and Parcel all implement this pattern in order to reduce unnecessary GC calls. The example with the

preceding Pair class is basically a copy of the Message class implementation. When using this approach,

remember to call recycle once you’re done with an object that implements this, or the pool will be empty all

the time.

Multithreading on Android

One of the most difficult parts of programming is when you have to write code that executes on multiple

threads. It’s a requirement for modern applications because you can’t have everything executing in a serial

order on one single thread. An Android application starts with a thread called main, also known as the UI thread

(in this book, I use main and UI thread interchangeably). Unless you start another thread or implicitly call a

function that starts a new thread, everything you do in an Android application will execute on the main thread.

This means that if your code performs an operation on the main thread (say, running code in the onResume

method) that will take a significant amount of time, all drawing and input events will be blocked until that

operation is completed. So, the first thing to remember when you start writing your application code: Make sure

that any code you execute won’t ever block the main thread.

But how do you know if a method is executing on the main thread? The official Android documentation

states: “By default, all components of the same application run in the same process and thread (called the ‘main’

thread)." More specifically, all the callbacks (basically, all the onX methods) in the Android components

(Activity, BroadcastReceiver, Service, and Application) are executed on the same thread. The

onStartCommand method of a Service is thus running on the same thread as the onResume of your

Activity. Remember this when you design your code because blocking one of these methods will cause the

system to “kill” your application.

The main thread in Android will run as long as your application’s process is alive. It is kept alive during the

application life cycle by the Looper class. This class creates a loop inside the current thread that queries a

message queue (using the MessageQueue class). The query to this queue will block until a new message has

arrived, which ensures that the thread sleeps when there’s nothing to do. All execution on the main thread is

done by sending messages to this queue, either directly through a Handler object or indirectly through some

part of the Android API (for instance, the runOnUiThread method). You can retrieve the Looper for the main

thread of your application through Context.getMainLooper().

What is safe to execute on the main thread and what should be moved to a different thread? To be very strict,

only the methods that must be executed on the main thread should be executed there. Everything else should

go on a separate thread. For practical reasons, you can bend this rule in some cases where the operation

you perform will never take a long time. If you make sure that any file, database, or network operations are

performed on a separate thread, you are usually safe. Also, for certain applications and games, you will perform

calculations at regular intervals that don’t directly have anything to do with the UI, and these should also

execute on a separate thread. However, it’s also important to ensure that you don’t have too many threads

running at the same time because a performance penalty is involved when the CPU switches from one thread

to another. In later chapters in this book, I give more specifics on when and when not to put your code on a

separate thread.

How do you declare and manage your threads when writing Android code? In the following section I show you

several ways to spawn new threads, and I explain each of these methods in detail, including their pros and cons.

Thread

This is the base class for all threads in Android. It is the same class as found in Java SE, and it behaves the same

way. If you want to execute something inside a thread, you can either make a specialization (that is, a new class

that extends Thread) or create a class implementing the Runnable interface that you pass to the constructor

of Thread. This example uses the latter option.

In this example, you need to iterate over an array of Objects in order to “upload” data to a server (the actual

code for uploading is not part of this example). You need to execute this operation on a separate thread;

otherwise, it will block the user interface. Also, the operation needs to update its progress by increasing a

ProgressBar. The following code shows an implementation of Runnable that resolves this issue:

public class MyThread implements Runnable {

private Object[] mInput;

private Activity mActivity;

private int mProgress = 0;

public MyThread(Activity activity, Object ... input) {

mActivity = activity;

mInput = input;

}

@Override

public void run() {

mProgress = 0;

Runnable runnable = new Runnable() {

public void run() {

mActivity.findViewById(R.id.progressBar).

setVisibility(View.VISIBLE);

((ProgressBar) mActivity.

findViewById(R.id.progressBar)).setProgress(0);

}

};

mActivity.runOnUiThread(runnable);

// Loop through and process mInput

for (Object input : mInput) {

// Post the input to a server (fake it with a sleep)

SystemClock.sleep(50);

runnable = new Runnable() {

public void run() {

((ProgressBar) mActivity.

findViewById(R.id.progressBar)).

setMax(++mProgress);

((ProgressBar) mActivity.

findViewById(R.id.progressBar)).

setProgress(mInput.length);

}

};

mActivity.runOnUiThread(runnable);

}

runnable = new Runnable() {

public void run() {

mActivity.findViewById(R.id.progressBar).

setVisibility(View.INVISIBLE);

}

)

};

mActivity.runOnUiThread(runnable);

}

}

As you can see in the preceding example, you need to create a new Runnable every time you want to update

the UI. This makes the code messy and will also cause unnecessary object allocations that need to be garbage

collected, which is always a bad thing. The Runnable is needed in order to post UI updates back to the main

thread through the runOnUiThread method.

There’s another problem with this solution: Because you can call start on an instance of Thread only once,

you must create a new Thread object every time you need to perform this operation. A new thread is an

expensive thing to create again and again, so there is definitively room for improvement here. All together, this

is not a very flexible method, and I discourage the direct use of the Thread class.

AsyncTask

This class is probably one of the more popular classes in Android because it is so simple to use. It allows you

to define a task that will run on its own thread and provide callbacks for the different stages of the task. The

callbacks are also designed to remove the need for using the runOnUiThread method to update the UI while

it’s running, which makes it very appropriate for indicating the progress of a long-running operation. Here is an

AsyncTask that does the same thing as in the Thread example:

public class MyAsyncTask extends AsyncTask<String, Integer, Integer> {

private Activity mActivity;

public MyAsyncTask(Activity activity) {

mActivity = activity;

}

@Override

protected void onPreExecute() {

super.onPreExecute();

// This will run on the main thread

mActivity.findViewById(R.id.progressBar).

setVisibility(View.VISIBLE);

((ProgressBar) mActivity.findViewById(R.id.progressBar)).

setProgress(0);

}

@Override

protected Integer doInBackground(String... inputs) {

// This will run NOT run on the main thread

int progress = 0;

for (String input : inputs) {

// Post the input to a server (fake it with a sleep)

SystemClock.sleep(50);

publishProgress(++progress, inputs.length);

}

return progress;

}

@Override

protected void onProgressUpdate(Integer... values) {

// This will run on the main thread

((ProgressBar) mActivity.findViewById(R.id.progressBar)).

setMax(values[1]);

((ProgressBar) mActivity.findViewById(R.id.progressBar)).

setProgress(values[0]);

}

@Override

protected void onPostExecute(Integer i) {

super.onPostExecute(i);

// This will run on the main thread

mActivity.findViewById(R.id.progressBar).

setVisibility(View.INVISIBLE);

}

}

In the preceding example, you see the implementation of four callbacks with a comment regarding which

thread they will execute on. As you can see, onPreExecute, onProgressUpdate, and onPostExecute

are all executed on the main thread, so it is safe to update the UI from these. publishProgress is also called

for each input to trigger the onProgressUpdate callback so that you can update a progress bar.

This class makes it much easier to perform long-running operations on a different thread and still be able to

communicate easily with the main thread when needed. The only problem with AsyncTask is that you can

use each instance of this class only once, which means that you have to call new MyAsyncTask() every time

you want to perform this operation. Although this class is not a heavyweight—the actual thread is managed

by an ExecutorService behind the scenes—it is not suitable for operations that you perform frequently

because you would quickly gather up objects that need to be garbage collected and eventually cause your

application’s UI to stutter.

In addition, you cannot schedule the time for the execution of this operation or perform the operation at a

certain interval. The AsyncTask class is suitable for things like file downloads or similar situations that will

happen relatively infrequently or by user interaction. Nevertheless, because it’s so easy to implement, this is

likely to be the class you will use at first in your application.

Handler

When you need a more fine-grained control for executing operations on a separate thread, you have a great

utility at your disposal in the Handler class. This class allows you to schedule operations with exact precision,

and you can reuse it as many times as you want. The thread that executes the operations loops until you

explicitly terminate it; the class Looper takes care of this behind the scenes. You will rarely need to set up your

own Looper ; instead, you can create it through the wrapper called HandlerThread. The following example

shows how to create a new Handler in your Activity.

public class SampleActivity extends Activity implements Handler.Callback

{

private Handler mHandler;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

// Start a new thread with a Looper

HandlerThread handlerThread

= new HandlerThread(“BackgroundThread”);

handlerThread.start();

// Create your new Handler

mHandler = new Handler(handlerThread.getLooper(), this);

}

@Override

protected void onDestroy() {

super.onDestroy();

// Shut down the Looper thread

mHandler.getLooper().quit();

}

@Override

public boolean handleMessage(Message message) {

// Process incoming messages here...

// Recycle your message object

message.recycle();

return true;

}

}

With your new Handler object, you can now safely schedule operations with exact precision. The usual way

of working with a Handler is by sending Message objects, which are simple, cheap, and reusable objects

for passing data and arguments to your background thread. A Message object is usually defined by its public

integer field name what that works as a flag that can be used in a switch-case statement in the callback

handleMessage. There are also two integer fields named arg1 and arg2 that are suitable for low-cost

arguments, as well as a field name obj for storing a single arbitrary object reference. If needed, you can also

add a set of more complex data using the setData method with a standard Bundle object. You can send your

messages to the handler using a number of methods. The three most common ones are demonstrated here:

public void sendMessageDemo(Object data) {

// Create a new Message with data as a parameter

// and send it for execution on the handler immediately

Message.obtain(mHandler, SYNC_DATA, data).sendToTarget();

// Send a simple empty message on your handler immediately

mHandler.sendEmptyMessage(SYNC_DATA);

// Send a simple empty message to be executed 30 seconds from now

mHandler.sendEmptyMessageAtTime(SYNC_DATA,

THIRTY_SECONDS_IN_MILLISECONDS);

// Send a message with both arguments fields and

// the obj set to be executed in two minutes.

int recipient = getRecipientId();

int priority = 5;

Message msg = mHandler.obtainMessage(SYNC_DATA, recipient,

priority, data);

mHandler.sendMessageDelayed(msg, TWO_MINUTES_IN_MILLISECONDS);

}

The first two examples show that you can create and send messages through both the Message class and the

Handler object. In the third and fourth example, you see how to schedule the message for processing with

millisecond precision.

When the Message is processed from the message queue, it will be sent, on the looping thread, to the callback

you’ve implemented. You can use the same callback for multiple Handler objects, which makes it useful as a

proxy-like method for dealing with the messages in your application. You can even share the callback between

Activities and Services. The most optimal way of implementing your callback is by keeping all the

constants representing the what value of a Message in the same class that implements the callback and then

use a standard switch-case statement to handle each message type. In the preceding example, I implemented

the callback on the Activity, but it can often be useful to have a separate class for this that you pass your

application’s Context to so that it can be used in all parts of your application. Here is an example of a typical

callback:

// Constants used for the what field in a Message

public static final int SYNC_DATA = 10;

public static final int PING_SERVER = 20;

@Override

public boolean handleMessage(Message message) {

switch (message.what) {

case SYNC_DATA:

// Perform long-running network I/O operation

syncDataWithServer(message.obj);

break;

case PING_SERVER:

// Ping your server. This should be called at regular intervals

pingServer();

break;

}

// Recycle your message object to save memory

message.recycle();

return true;

}

The handleMessage callback in this example has only two operations implemented, SYNC_DATA and

PING_SERVER. The first one will probably be triggered by a user event—for example, when a file is saved or

new data is ready to be posted to a server. The second one is supposed to execute at regular intervals. However,

there is no method on the Handler class for sending messages at an interval, so you need to implement that

behavior.

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();

}

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);

}

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.

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