What do I use now that Handler is deprecated?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
On Android, Handler as a concept is not fully deprecated. The part that commonly triggers warnings is the no-argument constructor, because it implicitly relies on the current thread's Looper, which makes thread targeting too easy to get wrong.
What Is Actually Deprecated
Code like this is the usual problem:
That constructor hides which thread will receive the posted work. If the current thread does not have the expected Looper, the behavior can be wrong or fragile.
The direct replacement is to pass an explicit Looper:
This makes the target thread explicit and removes the ambiguity that caused the deprecation warning.
Use Higher-Level APIs When They Match the Job Better
Even though Handler is still valid in some cases, modern Android code often has better options depending on intent.
If you are updating a View, use the view itself:
If you need general background work, use an executor:
If your project uses Kotlin coroutines, that is often the clearest option:
These APIs usually express intent more clearly than a raw message queue.
Main-Thread Execution Has Better Dedicated Options Too
If your only goal is to run something on the main thread, newer Android APIs can express that more directly than a generic handler. For example, a main-thread executor makes the destination explicit without exposing message-queue details:
This is often a better fit for one-off UI dispatch than carrying a long-lived handler field around an entire class.
Use HandlerThread Only When You Need a Looper Thread
Some older APIs still expect a looper-backed thread. In that situation, HandlerThread plus a Handler is still legitimate.
This pattern is still useful when you truly need a message queue on a dedicated thread. But if you only need background execution, an executor or coroutine dispatcher is often simpler.
Think in Terms of Intent
A good migration rule is:
- use
Handler(Looper.getMainLooper())when you genuinely need handler-style posting on the main thread - use
View.postfor view-related UI scheduling - use executors for general background tasks
- use coroutines when the project is already coroutine-based
- use
WorkManagerfor durable deferred work that should survive process death
This is a better question than "What replaces Handler everywhere?" because there is no one universal replacement. The right answer depends on why the old handler existed.
Common Pitfalls
- Assuming the entire
HandlerAPI is obsolete when the main issue is the implicit constructor. - Replacing
Handler()with another API without making the target thread clearer. - Using
Handler(Looper.getMainLooper())for heavy background work. - Creating a
HandlerThreadwhen a plain executor would be simpler and easier to maintain. - Scheduling durable background work with a
Handlerwhen the task really belongs inWorkManager.
Summary
- The common deprecation issue is the no-argument
Handler()constructor, not the entireHandlertype. - If you still need a handler, create it with an explicit
Looper. - Prefer higher-level tools such as
View.post, executors, coroutines, orWorkManagerwhen they better match the job. - Choose the replacement based on intent, not just on API name similarity.
- The safest modernization step is to make thread ownership explicit everywhere.

