tezvyn:

Handler and Looper: Android's Threading Backbone

AI-drafted, machine-checkedSource: developer.android.comadvanced

A Looper is a worker that endlessly processes a queue of tasks for a thread. A Handler is how you give that worker a new task from another thread, like updating the UI. The footgun is blocking the main thread's Looper, which freezes your app.

WHY IT EXISTS: Android's UI toolkit is not thread-safe, meaning only the main thread can safely modify UI components. This creates a problem: how do you perform long-running operations like network requests without freezing the UI, and then communicate the result back to update the screen? Handler and Looper provide the fundamental messaging system to solve this.

THE MENTAL MODEL: Think of a Looper as a dedicated assembly line worker for a single thread, endlessly processing items from a conveyor belt (the MessageQueue). Other threads can't place items on the belt directly. Instead, they give their tasks to a Handler, which acts as a dispatcher, placing the task onto the correct conveyor belt to be processed in order by the Looper.

HOW IT WORKS: A thread gets a Looper by calling Looper.prepare(), which creates a MessageQueue for it. Calling Looper.loop() starts an infinite loop, pulling Messages or Runnables from the queue and executing them. A Handler is always tied to a specific Looper and its thread. When you call handler.post(runnable), the Handler enqueues that work into the Looper's MessageQueue. The Looper eventually dequeues and executes it on its own thread. The main UI thread has a Looper created by the system at startup, so you can always post to it.

WHEN TO USE IT: The primary use is to communicate from a background thread to the main UI thread. After a background task completes, you use a Handler associated with the main Looper to post a UI update. You can also use this pattern to create your own dedicated background threads that process tasks sequentially, one after another, which is useful for stateful operations that shouldn't run in parallel.

WHEN NOT TO USE IT: For most modern application development, higher-level abstractions like Kotlin Coroutines are preferred for managing background work and concurrency. Coroutines provide structured concurrency, better cancellation, and cleaner error handling, abstracting away the manual Handler/Looper mechanism. Use Handlers directly when you need a simple sequential task queue or for low-level framework interaction.

ONE CANONICAL EXAMPLE: To update a TextView from a background thread, you first get a Handler for the main thread's Looper: val mainHandler = Handler(Looper.getMainLooper()). From your background thread, you then post your UI update work: mainHandler.post { myTextView.text = "Updated from background!" }. This lambda will be executed safely on the main thread.

Read the original → developer.android.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.