Skip to main content

How to handle messages from multiple threads using a Handler in Kotlin Android

How to handle messages from multiple threads using a Handler in Kotlin Android.

In Android development, it is common to have multiple threads running concurrently to perform various tasks such as processing data, fetching data from the network, or performing heavy computations. However, updating the user interface (UI) from a background thread is not allowed and can lead to crashes or unpredictable behavior. To overcome this limitation, Android provides a mechanism called Handler that allows you to send and process messages between threads. In this tutorial, we will learn how to handle messages from multiple threads using a Handler in Kotlin Android.

Step 1: Create a Handler

To handle messages from multiple threads, we need to create a Handler object. The Handler class provides a simple way to send and process messages between threads.

val handler = Handler()

Step 2: Send Messages from a Background Thread

To send a message from a background thread to the main thread, we can use the Handler object we created. The sendMessage() method can be used to send a Message object to the handler's message queue.

val backgroundThread = Thread {
// Perform some background task

val message = handler.obtainMessage()
message.what = SOME_CONSTANT // Set a constant value to identify the message

// Add additional data to the message if needed
message.obj = someData

handler.sendMessage(message)
}

backgroundThread.start()

In this example, we create a background thread using the Thread class and perform some background task. We then create a Message object using the obtainMessage() method of the handler. We set a constant value (SOME_CONSTANT) to identify the message and attach additional data (someData) if needed. Finally, we send the message using the sendMessage() method of the handler.

Step 3: Process Messages on the Main Thread

To process messages received from the background thread on the main thread, we need to override the handleMessage() method of the Handler class.

val handler = object : Handler() {
override fun handleMessage(message: Message) {
when (message.what) {
SOME_CONSTANT -> {
// Handle the message with the constant value SOME_CONSTANT
val data = message.obj // Get additional data attached to the message if needed

// Update the UI or perform any other task on the main thread
}
// Handle other messages if needed
}
}
}

In this example, we override the handleMessage() method of the Handler class to process the received message. We use a when statement to handle different constant values (SOME_CONSTANT) and perform specific tasks based on the message type. We can also access any additional data attached to the message using the obj property of the Message object.

Step 4: Cleanup

To avoid memory leaks, it is important to clean up the Handler object when it is no longer needed. This can be done by removing any pending messages and callbacks associated with the handler.

handler.removeCallbacksAndMessages(null)

The removeCallbacksAndMessages() method removes all pending messages and callbacks from the handler's message queue. Passing null as the parameter removes all messages and callbacks, but you can also specify a specific object or callback to remove.

Example: Updating UI from a Background Thread

Let's consider an example where we want to fetch data from a network API in a background thread and update the UI with the retrieved data. We can use a Handler to achieve this.

val handler = object : Handler() {
override fun handleMessage(message: Message) {
when (message.what) {
FETCH_DATA -> {
val data = message.obj as String // Get the data from the message

// Update the UI with the fetched data
textView.text = data
}
}
}
}

val backgroundThread = Thread {
// Fetch data from the network API
val data = fetchData()

val message = handler.obtainMessage()
message.what = FETCH_DATA
message.obj = data

handler.sendMessage(message)
}

backgroundThread.start()

In this example, we create a handler to update the UI. We then create a background thread to fetch data from a network API using the fetchData() function. Once the data is fetched, we create a message with the fetched data and send it to the handler using the sendMessage() method. In the handleMessage() method, we update the UI with the fetched data.

By using a Handler, we ensure that the UI is updated on the main thread, even though the data fetching is performed in a background thread.

Conclusion

In this tutorial, we have learned how to handle messages from multiple threads using a Handler in Kotlin Android. We saw how to create a Handler, send messages from a background thread, process messages on the main thread, and clean up the Handler when it is no longer needed. By using a Handler, we can safely update the UI from background threads and avoid crashes or unpredictable behavior.