Handler class allows you:

  • to schedule messages and runnables to be executed at some point in the future, for example methods post(Runnable) and sendMessage(Message)
  • to enqueue an action to be performed on a different thread than your own

Looper class used to create a message queue and run a message loop for a thread.

To create handler instance you need to specify Looper object, or create handler in thread that has Looper. For example, you can create Handler in the main thread to allow a background thread to change UI.

HandlerThread class represents a regular thread with looper, so you can create handler for such threads (see started service example.

Looper keeps a thread alive, you can terminate thread via quit() method of Looper.

Message class defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.

While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

Handler in main thread example
class MainActivity : AppCompatActivity() {
    val handler = Handler()
    val txtView : TextView by lazy {findViewById(R.id.txtScore)}
    // let's method invoked from background thread
    fun taskInBackground(){
       // ...
       handler.post{ // execute in main thread
           txtView.text = ...   
Looper thread example
class LooperThread : Thread() {
    lateinit var mHandler: Handler
    override fun run() {
        mHandler = object : Handler(Looper.myLooper()!!) {
        override fun handleMessage(msg: Message) {
                // process incoming messages here