Threading With HandlerThread in Android
You will learn how to use HandlerThread to receive messages from a Runnable in an Activity and pass them back to a UI handler to update the UI. By Amanjeet Singh.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Threading With HandlerThread in Android
20 mins
- Getting Started
- HandlerThread and its Components
- Creating Your Own HandlerThread
- Creating a Handler Bound to OrderHandlerThread
- Sending Messages With the Handler
- Setting Up the Created Handler
- Managing Runnable and Updating UI
- Updating UI and Other Initializations
- Cleaning Up
- Summary of Interaction Between Threads
- Use Cases of HandlerThread
- Comparison With Other Options
- Where to Go From Here?
Responsiveness is one of the most valuable features of any app. This is even more important in resource-constrained devices like smartphones. Users must be able to interact with the app in a smooth way without falling into flickering or a slow UI. For these reasons, concurrent programming must now be a part of the skillset of every developer.
It’s very important to know that all the interactions with UI components in an Android app happen on a single thread that we call the main thread — or, simply, the UI thread. Experience in other environments (Swing, AWT and others) teaches that the best approach is the one that translates every operation on the UI into a message to a single consumer that runs on the main thread. In Android, you can do this in many ways using different tools. HandlerThread is one of these.
In this tutorial, you’ll develop a handy food-ordering app that needs concurrent programming to execute its tasks. McWenderlich, a live-updating food-ordering app for a restaurant, will process the incoming orders by converting prices from USD to Indian Rupees (INR). The app can also attach additional side orders to a main order. Along the way you’ll learn:
The typical HandlerThread use cases.
- The core components of the HaMeR framework: Handler, Message and Runnable, and other two relevant classes: Looper and MessageQueue.
- The role of HandlerThread in the framework.
- How to create your own HandlerThread implementation to update the UI.
- How HandlerThread compares with other tools like AsyncTask, Service and IntentService.
The typical HandlerThread use cases.
Prerequisite: This tutorial assumes you are already familiar with the basics of Android development. If you are completely new to Android development, read through our Beginner Android Series. Other prerequisites include basic knowledge of threads and multi-threading.
Prerequisite: This tutorial assumes you are already familiar with the basics of Android development. If you are completely new to Android development, read through our Beginner Android Series. Other prerequisites include basic knowledge of threads and multi-threading.
Getting Started
As a first step, download the materials for this tutorial by clicking the Download materials button at the top or bottom of the tutorial. Once you’ve downloaded the materials, open the starter project in Android Studio 3.1.3 or later and get familiar with its content.
You should see:
-
FoodListAdapter: An adapter class for the
RecyclerView
of different food orders containing the order’s name, price in INR and the side order. -
FoodOrder: A model class for ordered food with three variables:
foodName
,foodPrice
andsideOrder
. -
FoodRunnable: A
Runnable
implementation, which will allow the creation of orders to send to a background thread, which will do the processing operations. -
MainActivity: An
Activity
where you have live updating food orders with their respective details.
Build and run the project. You’ll see a blank screen, which for now just shows an empty RecyclerView
:
This isn’t what you want. The UI should display the new orders as soon as our hungry customers create them. You need to manage orders in the background and display them in the list. This is a typical problem that HandlerThread can solve. But before implementing this, you’ll dive into the theory of HandlerThread.
HandlerThread and its Components
In Android, the HaMeR framework allows for interaction between any pair of threads, which can be any background thread and the main thread. In order to avoid race conditions and deadlocks, a thread can execute operations simply reading messages from a queue and executing them in sequence. When thread A wants to interact with thread B, thread A puts a message into the related queue. This can be done using a Handler object.
In more detail, the actors of this framework are:
- Handler: This is the most important object of the framework because of its double responsibility. It’s bound to a specific Looper for a given thread, and it provides the methods for sending messages to the related MessageQueue. The Handler is also responsible for the actual execution of the Message content.
- Message: Encapsulates the information about the operation you want to execute on a specific thread.
- Runnable: Interface that abstracts any operation that a thread can execute.
- MessageQueue: As the name suggests, this represents the queue of messages that a thread consumes.
- Looper: This is the object responsible for the loop that checks the MessageQueue to see if there is message to run and send it to a specific Handler. Every thread can have only one Looper.
.
But what’s the role of the HandlerThread class in all of this? As you’ll soon see, it’s a class that simplifies the creation of a Looper and related Handler instances in the case of background threads.
Now, time to start writing code!
Creating Your Own HandlerThread
In Android Studio, right-click on the com.raywenderlich.mcwenderlich root package folder and select New ▸ Kotlin File/Class. Next, name it OrderHandlerThread and select Class for Kind. Make it extend HandlerThread
.
The constructor of HandlerThread
requires a String
as parameter. This String
parameter is a name you can use to identify the thread during the debug. You can use the name of the class itself as the identifier, getting something like this:
class OrderHandlerThread : HandlerThread("OrderHandlerThread") {
}
Now, add a UiHandler
property to the primary constructor, which is a handler that corresponds to your main thread. This class handles UI changes in MainActivity based on the messages it receives. This class is available for you in the MainActivity class. OrderHandlerThread
should now look like this:
class OrderHandlerThread(private var uiHandler: MainActivity.UiHandler) :
HandlerThread("OrderHandlerThread") {
}
Add two variable declarations, for a Handler
and a random value, to the OrderHandlerThread
class:
class OrderHandlerThread(private var uiHandler: MainActivity.UiHandler) :
HandlerThread("OrderHandlerThread") {
private var handler: Handler? = null
private val random = Random()
}
Now, add the following two utility methods to this class. The first method convertCurrency
will help you convert the currency of foodPrice
:
/**
* Converts the food price from USD to Indian Rupees (INR).
* 1 USD has been considered as equal to 68.45 INR.
* @foodPriceInDollars price of the food in USD.
*/
private fun convertCurrency(foodPriceInDollars: Float): Float {
return foodPriceInDollars * 68.45f
}
The second method attachSideOrder
attaches additional random side to each of the upcoming orders:
/**
* Attaches random side order to the incoming food orders.
*/
private fun attachSideOrder(): String {
val randomOrder = random.nextInt(3)
return when (randomOrder) {
0 -> "Chips"
1 -> "Salad"
else -> "Nachos"
}
}
You need to create three more methods in the OrderHandlerThread
class:
-
getHandler
prepares theHandler
object bound to the correspondingOrderHandlerThread
, which you will use to perform the actual operations of converting the currency and attaching a side order to the upcomingfoodOrder
. -
sendOrder
gets the correspondingfoodOrder
and passes it to theHandler
for operations. -
onLooperPrepared
helps to setup the handler with a looper.
Let’s take a look at those now.