Looking Back Into HandlerThread Android Internal💫

Photo by amirali mirhashemian on Unsplash

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 👏

Related Posts

--

--

--

We are here building a community here.

Recommended from Medium

You Made It, Now…Deploy That App!

Building document scanner with opencv and python

Terraform & PagerDuty — Before You Try

How to Build a fuel logger “Android App” Guided by Tests

Reflections on 4 years of Google I/O and Udacity

Bubble sort

list for bubble sort

Run MinIO as Daemon

Raptor! My new tool for web automation

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Debanshu Datta

Debanshu Datta

Android @Gojek | Mobile Developer | Backend Developer (Java/Kotlin)

More from Medium

How to catch exceptions from Kotlin Flow?

Parallel Job in Coroutine using Kotlin…

Gradle Task Ordering

Open camera and display image using kotlin