Understanding Handler and Looper in Android

Rahul Rastogi
EXSQ Engineering Hub
4 min readMay 9, 2019
Photo by Priscilla Du Preez on Unsplash

Handler? For most of the android app developers, Handler provides just a way to execute some code on UI thread from Background/Worker thread.

That’s true, no doubt! Really..! But Handler is not limited to providing access to UI thread only. For understanding Handler more, I’ll have to take you on its components: Thread and Looper.

Threads in android work in a way like they start, execute their code block written in run() method and then get destroyed.

What if I want my thread to keep on running in andorid? Just like UI thread!

What if I want to pass some data/message to that running thread when I want from other threads?

Here comes Looper in picture. Looper, as the name implies, provides Thread an ability to keep on running in a loop and associates a MessageQueue for the thread on which this Looper object is created. When a Message/Runnable is posted, Looper executes those on its associated thread.

Note that, only one Looper can be created per Thread. It implies one MessageQueue per thread also. But multiple Handler can be created for a single Looper.

So, Looper is providing Thread an ability to run in a loop with its own MessageQueue.

Now, Handler provides a way to communicate with Looper. Handler sends Runnable/Message object on Looper, providing a way to execute code on a particular thread from another thread.

Each Handler always have a Looper object associated with it. Whenever we post a Runnable or send a Message on a Handler, it actually executes on the Thread associated with the Handler’s Looper.

UI thread also has a Looper and that is created by Android environment. So, while creating Handler on UI thread we don’t need to create a Looper.

By default, a background threads has no Looper associated with it. So, we’ve to create a Looper if we want to create a Handler for this background thread.

Handler executes the requests in a synchronous manner. But you can create a Handler which executes requests in Asynchronous manner too.

Contrary to what we’ve seen so far in which Handler runs code on UI thread. Now, I’m gonna show you how to run a code on background thread using Handler:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

var backgroundHandler: Handler? = null

//Creating a background thread.
val backgroundThread = Thread {
//Creating a Looper for this thread.
Looper.prepare()

//Looper.myLooper() gives you Looper for current Thread.
val myLooper = Looper.myLooper()!!

//Creating a Handler for given Looper object.
backgroundHandler = Handler(myLooper,
object : Handler.Callback {

//Processing incoming messages for this Handler.
override fun handleMessage(msg: Message?):
Boolean {
//Receiving extras from Message
val bundle: Bundle? = msg!!.data

Log.d("", "Handler:: Extras: ${bundle}")

Log.d("", "Handler:: Background Thread ID ${Thread.currentThread().id}")

//myLooper.quit()
return true
}
})

Looper.loop()
}

backgroundThread.start()

//Click listener on a Button
btn_launch.setOnClickListener {
Log.d("", "Handler:: UI Thread ID ${Thread.currentThread().id}")

//Executing code on backgroundThread using Handler.
backgroundHandler!!.post {
//Here, you'll note that Thread's ID is of backgroundThread.
Log.d("", "Handler:: Background Thread ID ${Thread.currentThread().id}")
}

// Now, sending data on backgroundThread using Message object. Handler's handleMessage(msg: Message?) method will receive this Message and perform appropriate action.
val extras = Bundle()
extras.putInt("PRICE", 100)
extras.putString("PRODUCT_NAME", "Table Lamp")

val message = Message.obtain(backgroundHandler)
message.data = extras

backgroundHandler?.sendMessage(message)
}
}

}

Running above code, you’ll analyze from Logcat that the Thread ID for code executed using backgroundHandler.post() and backgroundHandler.sendMessage() is always same. Since, both of the codes run on same background Thread. And Thread ID for UI thread is always different than that of background thread.

When you’re done with Thread loop and you want the Thread to be destroyed don’t forget to call looperObj.quit()

Handler class provides following utility methods to execute code using Runnable and sending Message on MessageQueue:

public final boolean post(Runnable r)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtFrontOfQueue(Runnable r)
public final boolean sendMessage(Message msg)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendMessageAtFrontOfQueue(Message msg)

These methods will help you to use Handler in multiple ways. Though, there are other classes provided by java like: Executors or ThreadPoolExecutor which ease out dealing with threads in a powerful way. But still, Handler is a standard way in android apps to use Queue system in a multi-threaded environment in an elegant way.

Thanks! Don’t forget to clap if you liked this post :)

--

--

Rahul Rastogi
EXSQ Engineering Hub

Mobile Apps @EX2 solutions, India. Technology enthusiast, Flutter, Android and more.