Android Why can't I create a handler in new thread
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A Handler is not just a callback utility. It is a thin wrapper around a thread's MessageQueue, which means the thread must have an active Looper before a Handler can be created.
That is why code that works on the main thread often crashes on a plain background thread with the message about calling a Handler on a thread that has not called Looper.prepare().
How Handler, Looper, and MessageQueue Fit Together
Android threads do not automatically process queued messages. The main thread is special because the framework starts a Looper for it during app startup. A plain Thread does not get that setup.
The relationship looks like this:
- A thread may own one
Looper. - The
Looperowns oneMessageQueue. - A
Handlerposts work into that queue.
If the queue does not exist, the Handler constructor has nowhere to send messages. That is why this code fails:
On older Android APIs this typically throws an exception saying the thread has not called Looper.prepare().
Creating a Handler Correctly on a Background Thread
If you truly need a background thread with its own queue, you must prepare a Looper on that thread and then start looping. The low-level version looks like this:
This works, but it has an important cost: Looper.loop() blocks forever until the looper is quit. That means you now have to manage thread shutdown yourself.
For most Android code, HandlerThread is the better option because it bundles the correct setup:
HandlerThread creates a worker thread, prepares the Looper, and exposes it with getLooper(). That removes the fragile manual setup.
Why Explicit Loopers Are Better
Older Android code often used new Handler() with no arguments. That constructor binds to the current thread's Looper, which is convenient but also easy to misuse. On a background thread with no looper, it fails. On the main thread, it works, but the call site does not make the target thread obvious.
Being explicit is clearer:
This style makes the threading intention visible in the code and avoids relying on whichever thread happens to be executing the constructor.
Posting Back to the Main Thread
Another source of confusion is that many developers do not actually need a background Handler. They only need to send results back to the UI thread after doing work elsewhere.
In that case, do the heavy work on a background executor and post the UI update to Looper.getMainLooper():
This pattern is common because Android views must be touched from the main thread.
When to Use Newer APIs Instead
Handler is still valid, but it is not the best abstraction for every concurrency problem. If the job must continue even after the app process is backgrounded, WorkManager is usually more appropriate. If you are writing Kotlin, coroutines give you clearer structure for switching between background and UI work.
For example, in Kotlin with coroutines:
This does not replace every Handler, but it does replace a lot of the boilerplate that older Android apps used.
Common Pitfalls
The first pitfall is assuming every thread has a Looper. Only the main thread gets one automatically. Other threads need explicit setup or a helper like HandlerThread.
Another issue is forgetting to stop a HandlerThread. If you never call quit() or quitSafely(), the looper keeps waiting for work and the thread stays alive longer than intended.
It is also common to create a background Handler when only a main-thread Handler is needed. If the real goal is updating the UI after background work, keep the queue on the main thread and use an executor or coroutine for the heavy task.
Finally, do not use a Handler as a replacement for all long-running background work. For scheduled, deferrable, or guaranteed jobs, Android background APIs such as WorkManager are more robust.
Summary
- A
Handlerneeds a thread that already has aLooperandMessageQueue. - The main thread has a
Looperby default, but a plainThreaddoes not. - Use
HandlerThreadwhen you need a background thread with its own message loop. - Use
Looper.getMainLooper()when posting results back to the UI thread. - For many modern Android tasks, executors, coroutines, or
WorkManagerare simpler than managing a customHandlerthread.

