Drift Away From Android Handlers. Use Coroutines and Jobs Instead!
Timed tasks can be simplified using Coroutines and Jobs over a Handler. See how!

Scenario
We all have used Handlers with postDelayed
method to perform some task after a certain time duration in our Android applications. That was our go-to way for performing tasks with such kind of time requirements.
Using a Handler
, a typical code to perform a task after 10 seconds would look like this:
I think this is tedious!
The creation and maintenance of a Handler instance especially become tedious when there’s a scope that asks us to cancel the currently running timed task and we have multiple tasks running at the same time.
In this case, we’d have to maintain either a token or separate runnable instance for canceling the desired task in between, before the timer elapses.
Also, the provision of a Looper instance for Handler’s creation may seem a bit tedious and most of us tend to just use the default main looper (used in the above gist) which again causes some UI issues / Janks, etc.
Enter Coroutines and Jobs
Thanks to the Kotlin Coroutines and Jobs mechanism, we can get away from using Handlers in this scenario, by creating lightweight Coroutine Jobs and cancelling them in between to just stop the desired task from getting executed.
The above code using a Coroutine Job would look like this:
Instead of maintaining 2 separate instances of Handler
and a runnable, we can maintain only 1 instance of a Job.
Whenever we want to start a task, that executes after X seconds (10 seconds in this case) we can just cancel previously running job instance (this is optional, just to avoid inconsistent states) and create a new Job instance and get the reference of it.
The delay method used in the Job will suspend the task for X seconds (10 seconds in this case) and then resume the execution after it. And if we want to cancel the task in between, we can just cancel the Job! Pretty clean and simple, isn’t it?
Since Coroutines and Jobs are considered lightweight, creation of new Jobs each time won’t have any significant impact on performance. We can also use the desired dispatcher (for example, Dispatchers.IO
) to perform the task on, so no need of providing a fixed Looper
instance as in the case of a Handler, making code more thread-friendly and with lesser bugs!
Though Handler has its own use cases, we can surely use Coroutines and Jobs over it, for performing timed tasks in a neat manner.
What do you think about this approach? Would you like to improve it furthermore? Anything that you’re concerned about?