Mobile devices are getting pretty fast, but they aren’t infinitely fast yet. If you want your app to be able to do any serious work without affecting the user experience by locking up the interface, you’ll have to resort to running things in parallel. On Android, this is done with “threads”.
Grab yourself a cup of coffee and read this post line by line. I’ll introduce you to the concept of threads, talk about how Java uses threads and explain how “Handlers” in Android help with threading.
Whenever you want to do asynchronous/parallel processing, you do it with threads.
Threads you say ?
A thread or “thread of execution” is basically a sequence of instructions (of program code), that you send to your operating system.
“Typically” your CPU can process one thread, per core, at any time. So a multi-core processor (most Android devices today) by definition can handle multiple-threads of execution (which is to say, they can do multiple things at once).
Truth to multi-core processing and single-core multitasking
I say “typically” because the corollary to the above statement is not necessarily true. Single-core devices can “simulate” multithreading using multitasking.
Every “task” that’s run on a thread can be broken down into multiple instructions. These instructions don’t have to happen all at once. So a single-core device can switch to a thread “1” finish an instruction 1A, then switch to thread “2” finish an instruction 2A, switch back to 1 finish 1B, 1C, 1D, switch to 2, finish 2B, 2C and so on…
This switching between threads happens so fast that it appears, even on a single-core device, that all the threads are making progress at exactly the same time. It’s an illusion caused by speed, much like Agent Brown appearing to have multiple heads and arms.
Now on to some code.
Threads in core Java
In Java, when you want to do parallel processing, you execute your code in a
Runnable either by extending the
Thread class or implementing the Runnable interface
Both of these approaches are fundamentally very similar. Version 1 involves creating an actual thread while Version 2 involves creating a runnable, which in-turn has to be called by a Thread.
Threads in Android
Whenever your app starts up in Android, all components are run on a single primary thread (by default) called the “main” thread. The primary role of this thread though, is to handle the user interface and dispatch events to the appropriate widgets/views. For this reason, the main thread is also referred to as the “UI” thread.
If you have a long running operation on your UI thread, the user interface is going to get locked up until this operation is complete. This is bad for your users! That’s why it’s important to understand how threads work in Android specifically, so you can offload some of the work to parallel threads. Android is pretty merciless about keeping things off the UI thread. If you have a long running operation on the UI thread you’re probably going to run into the infamous ANR that will conveniently allow your users to kill your app!
Now Android is all Java, so it supports the usage of the core Java
Thread class to perform asynchronous processing. So you could use code very similar to the one shown in the “Threads in Java” section above, and start using threads in Android right away. But that can be a tad bit difficult.
Why is using core Java threads in Android difficult?
Well, parallel processing is not as easy as it sounds because you have to maintain “concurrency” across the multiple threads. In the words of the very wise Tim Bray:
ordinary humans can’t do concurrency at scale (or really at all) …
Specifically for Android, the following is additionally cumbersome:
- Synchronization with the UI thread is a major PITA (you typically want to do this, when you want to send progress updates to the UI, for your background operation)
- Things change even more weirdly with orientation/configuration changes because an orientation change causes an activity to be recreated (so background threads may be trying to change the state of a destroyed activity, and if the background thread isn’t on the UI thread, well that complicates things even more because of point 1).
- There’s also no default handling for thread pooling
- Canceling thread actions requires custom code
Arr…ok, so how DO we do parallel processing in Android?
Some (in)famous Android constructs you’ve probably come across:
This is the subject of our detailed discussion today
It requires more boiler plate code, but this is generally my preferred mechanism for off-loading long-running operations to the background. Armed with an EventBus like Otto, IntentServices become amazingly easy to implement.
These are geared more towards performing asynchronous tasks, that have to deal with data from databases or content providers.
If you’ve worked with Services closely, you should know that this is actually a little misleading. A common misconception is that Services run on the background thread. Nope! they “appear” to run in the background because they don’t have a UI component associated with them. They actually run on the UI thread (by default)…. So they run on the UI thread by default, even though they don’t have a UI component?
If you want your service to run on a background thread, you’ll have to manually spawn another thread and execute your operations in that thread (similar to an approach discussed above). Really you should just use IntentServices but that is a subject for another post.
From the not-so-dummy-friendly Android developer documentation for Handlers:
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue. Each Handler instance is associated with a single thread and that thread’s message queue. When you create a new Handler, it is bound to the thread/message queue of the thread that is creating it – from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
To understand that better, you probably need to know what Message Queues are.
Threads basically have something called a “Message Queue”. These message queues allow communication between threads and is a sort of pattern, where control (or content) is passed between the threads.
It’s actually a wonderful name, because it’s exactly just that: a queue of messages or sequence of instructions, for the thread, to perform one by one. This additionally allows us to do two more cool things:
- “schedule” Messages and Runnables to be executed at some point in the future
- enqueue an action to be performed on a different thread other than your own
Note: when I mention ‘message’ from here onwards, it’s the same as a runnable object or a sequence of instructions.
So going back to Handlers in Android…. if you read and pause at every single line, the docs make much more sense now:
A Handler allows you to send and process Message and Runnable objects associated with a thread’s MessageQueue.
So, a handler allows you to send messages to a thread’s message queue. check ✔ !
Each Handler instance is associated with a single thread and that thread’s message queue.
A handler can only be associated with a single thread. ✔
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it
So, which thread is a handler associated with? The thread that creates it. ✔
– from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
Yeah yeah we already know that. Moving on…
Tip: Here’s something you probably didn’t know : in Android, every thread is associated with an instance of a Handler class, and it allows the thread to run along with other threads and communicate with them through messages.
Another Tip (if you’ve dealt with the more common AsyncTasks): AsyncTasks use Handlers but don’t run in the UI thread. They provide a channel to talk back to the UI, using the postExecute method.
This is all cool yo, so how do I create them Handlers?
- using the default constructor: new Handler()
- using a parameterized constructor that takes a runnable object or callback object
What useful methods does the Handler API give me?
- Handlers simply send messages or “posts” to the message queues.
- They are convenience methods that help syncing back with the UI thread.
If you look at the API for Handlers now, the main methods provided make sense:
The examples below are rudimentary, what you actually want to be closely following are the comments.
Example 1: using “post” method of the Handler
If I didn’t have a handler object, posting back to the UI thread would have been pretty tricky.
Example 2: using postDelayed
In a recent feature for Wedding Party, I had to emulate the auto-complete functionality with an EditText. Every change in text triggered an API call to retrieve some data from our servers.
I wanted to reduce the number of API calls shot out by the app, so I used the Handler’s postDelayed method to achieve this.
This example doesn’t focus on parallel processing, but rather the ability for the Handler to function as a Message Queue and schedule messages to be executed at some later point in the future
I leave the “postAtTime” as an exercise for the reader. Got a grip on Handlers? Happy threading!