Many ways to run many tasks in Android

  1. How to use a Handler to post results on the Main Thread.
  2. How to use HandlerThread to run many tasks off the Main Thread and post results to the MainThread (no AsyncTask used).
  3. What is a Looper and how to create your own one.

We all have a point in our developer’s life where there are too many tasks to be run and we know that running them on the main thread is a ANR idea.

So let’s explore the right choices we have:

Using a Handler

We can easily run a task as Runnable and post the result from it to be processed on the main thread like this:

val handler = object:Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
message.text = msg.obj.toString()
}
}
val msg = Message.obtain()
msg.obj = "$name completed"
handler.sendMessage(msg)

Using a Handler with Looper.getMainLooper() you can use handler.sendMessage(msg) from another thread and receive the message on the Main Thread. Good but what if I have a lot of tasks to be run now? Here comes the HandlerThread.

Using a HandlerThread

You can run multiple tasks off the Main Thread extending or wrapping a HandlerThread. Here I will extend it:

class AndroidHandlerThread: HandlerThread {

private var handler: Handler? = null

constructor(): super(TAG){
start()
handler = Handler(looper)
}

fun execute(r: Runnable){
handler?.post(r)
}

companion object{
val TAG = "HandlerThreadWorker"
}

}
androidHandlerThread = AndroidHandlerThread()
tasks.forEach() {
androidHandlerThread?.execute(it)
}
private fun getTask(name: String): Runnable{
return object : Runnable {
override fun run() {
Thread.sleep(1000)
val msg = Message.obtain()
msg.obj = "$name completed"

//This is the Main Thread handler
handler.sendMessage(msg)
}
}
}

What exactly is a Looper?

It is very easy to understand what the Looper does if you create one of your own. Here it is:

class SimpleWorker : Thread(TAG){

companion object{
val TAG = "SimpleWorker"
}

private var alive: AtomicBoolean = AtomicBoolean(true)
private val tasksQueue = ConcurrentLinkedQueue<Runnable>()

init {
start()
}

override fun run() {
super.run()
while(alive.get()){
tasksQueue.poll()?.run()
}
}

fun execute(r: Runnable){
tasksQueue.add(r)
}

fun quit(){
alive.set(false)
}
}

You see. Looper is just one thread that is looping through a queue of tasks.

Here comes the loop:

while(alive.get()){
tasksQueue.poll()?.run()
}

Notice the usage of quit(). We need to have a way to quit because otherwise Looper will loop endlessly. This is why when using a HandlerThread you need to call quit at some point.

override fun onDestroy() {
simpleWorker?.quit()
super.onDestroy()
}

Good job, let’s go and run some tasks now.

Here is the whole project:

https://github.com/i-tanova/LooperProject

--

--

--

Android enthusiast and keen tea drinker. I love to learn and to be funny, both for me are passions.

Love podcasts or audiobooks? Learn on the go with our new app.

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
Ivana Tanova

Ivana Tanova

Android enthusiast and keen tea drinker. I love to learn and to be funny, both for me are passions.

More from Medium

Making Android Annotation Processor : Part 1

Android(Java, Kotlin) — Course Plan

Secure Coding

Mirror Your Android Phone on A Windows PC