Looking Back Into HandlerThread Android Internalđ«
Previously we looked into how MessageQueue, Looper and Handler Internal works together and we build it from scratch.
This way is good to understand the inner working of HandlerThread which internally works in the same way. It is the same that we can keep it running in the background and provide with more and more packages of work, which will be executed sequentially one after another.
Handler Thread
A Thread that has a Looper. The Looper can then be used to create Handlers
Working With Basic Handler Threadđ
First, we make an instance of Handler Thread. We shouldnât actually initialize the HandlerThread in Activity because of the Activity Lifecycle. But if we are doing it we should handlerThread.start()
in the on onCreate()
and do handlerThread.quit()
in the onDestroy()
. In this way, we will protect ourselves from zombie threads that will run indefinitely.
We already know that to get work into HandlerThread we need Handler. We will initialize it onCreate()
and pass Looper of the HandlerThread to the constructor threadHandler=new Handler(handlerThread.looper)
. By attaching the looper we put work into the HandlerThread and not into the UI Thread.
Now letâs put some work into the MessageQueue, by threadHandler.post(<Your Runnable/Message>)
You can do many other things besides just post, like postDelayed()
etc they are quite intuitive and easy to use play around with.
Another problem is the Anonymous Runnable inside will create a Potential Memory Leak, with an anonymous object. It has reference to the outer main class. So the Runnable here have reference to Activity. As long we have reference to the Activity canât be garbage collected. When the activity is destroyed and if the thread is running, since the thread has to reference activity it canât be garbage collected. One way is to make a static inner class and extend Runnable.
For this, we will create inner classes, alternatively, we make it a separate top-level class, which doesn't keep a reference to the activity so it doesn't keep it alive over its natural lifecycle.
inner class ExampleRunnable1 : Runnable {
override fun run() {
for (i in 0..3) {
Log.d(TAG, "Runnable1: $i")
SystemClock.sleep(1000)
}
}
}

Working with Messages in HandlerThreadđ
We start by making CustomHandlerThread which will extend HandlerThread. Firstly we will add the constructor, which will make it hardcoded.
The name is for debugging purposes and the second parameter priority is optional it decides how much processing time a thread should get because when you start multiple threads they have to be executed by the same CPU, It is good to tell the CPU how important a thread is so to decide how much attention it should get. You have to pass Process.THREAD_PRIORITY_BACKGROUND
which are integer constants there are multiple priority options, the default value is zero, and the higher the number lower is the priority. You can set the priority later also with the Process.priority
.
Now letâs add Handler to the HandlerThread, now we have to add this handler associated with the background thread. We have to put it inside the run()
method but it is already implemented by the HandlerThread superclass. In our last blog, we learned we have to initialize it in a very specific place, i.e after we call Looper.prepare()
and before Looper.loop()
so we have to override onLooperPrepared()
and initialize the handler here, we donât have to pass the looper since this will be executed in the background thread, so the handler will be attached to the background thread.



Removing Messages and Runnable from MessageQueueđą
We know that after we quit a thread we canât restart it like a normal Java Thread, we have to create a new instance. But we can also remove messages and runnable from the message queue without quitting the HandlerThread and keep it running.
We have to get the handler again. It is important to note that it should be the same one that puts that message or runnable in the MessageQueue before, i.e, A handler can only remove messages that it has set in the first place and canât remove messages of other handler instances.
// We can remove a message which is identified by what field taht we set above
handlerThread.handler.removeMessages(what:int)// We delete runnables by passing the same instance
handlerThread.handler.removeCallbacks(r:Runnable)// We have is method to remove both based on the Object Token
handlerThread.handler.removeCallbacksAndMessages(token:Object)
//In the above case if we pass null it will remove all pending messages
In this way, we are not interfering with the message/ runnable already running only the ones in the queue. So we canât avoid memory leaks just by quitting the HandlerThread because it doesnât interfere with the task that is already running only the ones about to be executed in the future.
For any doubts and suggestions, you can reach out on my Instagram, LinkedIn. Follow me for Kotlin content and more. Happy Coding!
I will well appreciate one of these đ