Handler() deprecated in Android? What to use in 2025

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Handler() deprecated: what now? A look at 2025

\n\n

If you've ever written for Android, you've probably used Handler() for switching between threads, delayed tasks, or updating the UI. This old reliable class has been with us since the earliest versions of Android. But in 2024-2025, Google officially declared the Handler() constructor deprecated. Thousands of developers on Stack Overflow are asking: «What do I use now that Handler() is deprecated?»

\n\n

In this article, we'll figure out why Handler() is deprecated, what alternatives Android offers in 2025, and most importantly — how to write modern, clean code in Kotlin that won't make your team lead cry. Let's go!

\n\n

Why did Handler() become deprecated?

\n\n

The Handler class itself hasn't gone anywhere. What is deprecated is specifically the no-argument constructor (Handler()) and its overloads that implicitly created a Looper from the current thread. The problem is that this behavior:

\n\n
    \n
  • Is implicit and unsafe — if you call Handler() in a background thread that doesn't have a Looper, you'll get a RuntimeException.
  • \n
  • Complicates testing — Handler is tightly coupled to the thread lifecycle, making unit tests a headache.
  • \n
  • Is morally outdated — more modern and declarative tools have emerged: coroutines, HandlerThread (explicitly), and LiveData.
  • \n
\n\n

Google recommends either explicitly passing a Looper to the constructor, or using alternatives. Let's look at what exactly has come to replace it.

\n\n

Alternative #1: Explicit Looper (the simplest fix)

\n\n

If you don't want to rewrite all your code, the fastest way to remove the deprecation is to pass a Looper explicitly. For the main thread (UI thread), use Looper.getMainLooper().

\n\n
// Old code (deprecated)\nval handler = Handler()\n\n// New code (2025)\nval handler = Handler(Looper.getMainLooper())\n\n// Or for a background thread:\nval handler = Handler(Looper.myLooper()) // Caution: may be null!\n
\n\n

This won't solve all problems, but it will remove the compiler warning. However, for serious projects, it's better to switch to coroutines.

\n\n

Alternative #2: Kotlin Coroutines (recommended by Google)

\n\n

Since 2021, Google has officially recommended Kotlin Coroutines for asynchronous operations. In 2025, this is already the industry standard. Why are coroutines better than Handler?

\n\n
    \n
  • Lightweight — thousands of coroutines don't block threads.
  • \n
  • Structured concurrency — automatic cancellation when the lifecycle ends.
  • \n
  • Readability — code looks synchronous, without callbacks.
  • \n
  • Testability — runBlocking and TestCoroutineDispatcher for unit tests.
  • \n
\n\n

Here's how to replace typical Handler tasks with coroutines:

\n\n

Replacing postDelayed (delayed task)

\n\n
// Old way with Handler\nval handler = Handler(Looper.getMainLooper())\nhandler.postDelayed({\n    // execute after 2 seconds\n}, 2000)\n\n// New way with Coroutines\nlifecycleScope.launch {\n    delay(2000) // doesn't block the thread!\n    // execute after 2 seconds\n}\n
\n\n

Replacing post (switching to UI thread)

\n\n
// Old way\nhandler.post {\n    textView.text = "Hello from background thread"\n}\n\n// New way\nlifecycleScope.launch(Dispatchers.Main) {\n    textView.text = "Hello from coroutine"\n}\n
\n\n

Replacing removeCallbacks (cancelling a task)

\n\n
// Old way\nval runnable = Runnable { /*...*/ }\nhandler.postD                

Blogs

Book Recommendations