Skip to content

What do I use now that Handler() is deprecated?

Alternative to deprecated handler Android

1. Overview

In this article, we will see the deprecated constructors of the handler and its alternative solutions in Android.

Normally, Android apps use the main thread to handle UI tasks and input events. So executing any long-running tasks on this main thread can lead to app freezes and unresponsiveness. This main thread collects the UI events or messages in a queue (MessageQueue) and then processes them using an instance of the Looper class. By default, the main thread already has a Looper prepared.

You can also create a thread with a looper.

This Looper helps to keep the thread alive and manages a message queue to execute tasks on that thread. It takes each message from the queue and executes it. A Handler gives you a mechanism to push tasks into this queue from any other threads. You can use Handler to add a Runnable object to the Looper to execute the code on the thread associated with the Looper.

We associate each Handler instance with a single thread and that thread’s message queue. Whenever you create a new Handler instance, it is tied up to a Looper. It will deliver messages and Runnables to that Looper’s message queue and execute them on that Looper’s thread.

In addition to Handler, Android supports the Thread class to perform asynchronous processing. Besides, it also supports the java.util.concurrent package to perform the background tasks such as ThreadPool and Executor. See our articles to know more about various Android concepts.

2. Deprecated constructors of the handler Android

 Only the following constructors of the Handler are deprecated.

  • Handler()
  • Handler(Handler.Callback)

The above constructors implicitly choose the local thread and its associated Looper to execute the background tasks. This can lead to bugs such as :

  1. Tasks lost silently (if the Handler is not expecting new tasks and quits)
  2. Crashes (it invokes the handler on a thread without a Looper active)
  3. Race conditions
  4. No control on the thread on which the handler executes.

To avoid using these deprecated constructors, Android suggests using the following solutions based on our use case:

  • Use an Executor
  • Specify the Looper explicitly.
  • Looper.getMainLooper() to retrieve and use the Looper of the main thread
  • If you require the implicit thread-local behavior for compatibility, use new Handler(Looper.myLooper(), callback).

The constructor new Handler(Looper.myLooper(), callback) is the exact alternative to the aforementioned deprecated methods. All these use the local thread to execute the background task.

3. Alternative to deprecated handler Android

Let’s see examples for each of these solutions.

3.1. Specify Looper explicitly to the Looper

You can use the Handler to enqueue an action to be performed on a different thread. To specify the thread on which to run the action, construct the Handler using a Looper for the thread. A Looper is an object that runs the message loop for an associated thread.

Once you’ve created a Handler, you can then use the post(Runnable) method to post the message to the Looper and later runs the Runnable block of code in the corresponding thread.

3.1.1. Run handler in main thread

Looper includes a helper function, getMainLooper(), which retrieves the Looper of the main thread. You can run code in the main thread by using this Looper to create a Handler.

val mainHandler = Handler(Looper.getMainLooper()).post {
            System.out.println("Thread : " + Thread.currentThread().name)
        }

2.1.2. Run handler in the current thread

To execute the handler in the current thread, then you have to retrieve the Looper of the current thread by using the Looper.myLooper method. The constructor new Handler(Looper.myLooper(), callback) is the exact alternative to the aforementioned deprecated methods. All these use the local thread to execute the background task.

val mainHandler = Handler(Looper.myLooper()).post {
            System.out.println("Thread : " + Thread.currentThread().name)
        }

3.1.3. Specify the Looper of any thread

Alternatively, you can create a thread with Looper and use it to execute the background task.

val handlerThread = HandlerThread("HandlerThread");
handlerThread.start();

val backgroundHandler = Handler(handlerThread.looper).post {
    println("Thread : " + Thread.currentThread().name)
    handlerThread.quitSafely(); 
}

3.1.4. Update main thread from another thread

You can create another Handler to update the UI thread from your background thread:

val backgroundHandler = Handler(handlerThread.getLooper(), Handler.Callback() {

        
        Handler(Looper.getMainLooper()).post {
            System.out.println("Thread : " + Thread.currentThread().name)

        }
        
        return true
    }
})

3.2. Use an Executor

3.2.1. Run executor in main thread

You can get the executor that can run tasks in the main thread by using the ContextCompat.getMainExecutor(this).

val mainExecutor: Executor = ContextCompat.getMainExecutor(this)


        mainExecutor.execute(Runnable {

        })

3.2.2. Run executor in a background thread

You can create an executor to execute the tasks in a background thread.

val backgroundExecutor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()


backgroundExecutor.execute {

    backgroundExecutor.shutdown();
}


backgroundExecutor.schedule({

    backgroundExecutor.shutdown();
}, 5, TimeUnit.SECONDS)

3. Conclusion

To sum up, we have seen the constructors that are deprecated in the Handler class and the alternative solutions with examples.

3 thoughts on “What do I use now that Handler() is deprecated?”

  1. Pingback: Handler in Kotlin - TedBlob

  2. Pingback: Android Kotlin - Handler and Runnable examples - TedBlob

  3. Pingback: Handler Handler New Handler? Quick Answer - Ko.taphoamini.com

Leave a Reply

Your email address will not be published. Required fields are marked *