1.Overview
In this article, we will learn about the Android Kotlin – Handler and Runnable along with examples.
2. Android Kotlin – Handler and Runnable
Normally, Android apps use the main thread to handle UI tasks and input events. This main thread collects these input events or messages in a queue (MessageQueue
) and then processes them using an instance of the Looper class. By default, the main thread already has a Looper prepared.
This Looper
keeps the main thread alive and manages the message queue. It takes each message from the queue and executes it on the thread.
A Handler gives you a mechanism to push tasks into this queue from any other threads thus allowing other threads to communicate with the UI thread. It doesn’t mean that the Handler supports only the main thread. It can push tasks to any thread’s queue that has a Looper.
You can use Handler to add a Runnable object or messages to the Looper to execute the code on the thread associated with the Looper.
Android associates each Handler instance with a single thread and that thread’s message queue. Whenever you create a new Handler instance, it is tied up to a single Looper
. So, it will deliver all the messages and Runnable to that Looper’s message queue.
There are two primary uses for a Handler:
- Schedule messages and Runnable to be executed in the future
- Enqueue an action to be performed on a different thread than your own.
Few Handler
constructors are deprecated which we have discussed separately in this article.
2.1. Schedule messages or Runnable
You can schedule messages by using the following methods:
post
postAtTime(java.lang.Runnable,long)
postDelayed
sendEmptyMessage
sendMessage
sendMessageAtTime
sendMessageDelayed
The above post
methods allow you to push Runnable
objects to the message queue.
The sendMessage
versions allow you to enqueue a Message
object containing a bundle of data to be processed by the Handler’s handleMessage
method. You had to create a subclass of the Handler class and implement the handleMessage
method.
You can create your own threads, and communicate back with the main application thread through a Handler.
3. Handler Kotlin examples
3.1. Handler post method Kotlin examples
As discussed earlier, you can use the Handler
to enqueue an action to be performed on a different thread. To specify the thread on which to run the action, construct the Handler
using a Looper
for the thread.
Once you’ve created a Handler
, you can then use the post(Runnable)
method to post the message to Looper’s message queue.
3.1.1. Run handler in main thread
Looper
includes a helper function, getMainLooper()
, which retrieves the Looper
of the main thread. You can run code in the main thread by using this Looper
to create a Handler
.
val mainHandler = Handler(Looper.getMainLooper()).post { System.out.println("Thread : " + Thread.currentThread().name) }
3.1.2. Run handler in the current thread
To execute the handler in the current thread, then you have to retrieve the Looper of the current thread by using the Looper.myLooper
method. All these use the local thread to execute the background task.
val mainHandler = Handler(Looper.myLooper()).post { System.out.println("Thread : " + Thread.currentThread().name) }
3.1.3. Specify the Looper of any thread
Alternatively, you can create a thread with Looper and use it to execute the background task.
val handlerThread = HandlerThread("HandlerThread"); handlerThread.start(); val backgroundHandler = Handler(handlerThread.looper).post { println("Thread : " + Thread.currentThread().name) handlerThread.quitSafely(); }
3.1.4. Update main thread from another thread
You can create another Handler to update the UI thread from your background thread:
val backgroundHandler = Handler(handlerThread.getLooper(), Handler.Callback() { Handler(Looper.getMainLooper()).post { System.out.println("Thread : " + Thread.currentThread().name) } return true } })
3.2. Handler sendMessage Kotlin examples
You can use sendMessage
to send a message object to Handler from any thread. The Handler receives the message object in the handleMessage
callback method.
After receiving and looking at the message object, you can organize what is being sent to the thread associated with the Handler and push Runnable
or message to the thread’s message queue accordingly.
For example, a thread sends bundle data to the Handler (incomingHandler
). The incomingHandler
receives the bundle data in the handleMessage
callback and uses the data to update the main thread (the main thread is associated with the incomingHandler
).
private val incomingHandler = IncomingHandler(this, Looper.getMainLooper()) Thread { try { val msg: Message = incomingHandler.obtainMessage() val bundle = Bundle() bundle.putString("MSG_KEY", "Executed in background thread") msg.data = bundle incomingHandler.sendMessage(msg) } catch (ex: Exception) { ex.printStackTrace() Toast.makeText(this, ex.message, Toast.LENGTH_LONG).show() } }.start() private class IncomingHandler(private val context: Context, looper: Looper) : Handler(looper) { override fun handleMessage(@NonNull msg: Message) { super.handleMessage(msg) val bundle = msg.data val displayMessage = bundle.getString("MSG_KEY") post { Toast.makeText(context, displayMessage, Toast.LENGTH_LONG).show() } } }
4. Conclusion
To sum up, we have seen the Android Kotlin – Handler and Runnable along with examples.