There are myriads of blog posts that showcase how to debounce the user’s input by using either rxjava or coroutines. The question is how to implement such a functionality when the project does not have these dependencies?
Debounce
First of all, what is debounce? In essence debounce is a pattern that helps in preventing the repeated execution of a block of code. It does that by adding a delay between two consecutive calls to the block and by cancelling the first call when the second is requested. For example:
When the user types in her keyboard, every key stroke results in calling a block of code that renders what she typed:

By having debounce when the user types, each call gets delayed and cancelled if a new one gets requested resulting in rendering the entire text when the user is finished typing:

Before starting
We are going to add the debounce functionality to the example above. The initial code is very simple:
where userInput
is the EditText
that the user writes in and userResult
is the TextView
that the user’s input gets rendered.
Adding the debounce functionality
There are two ways to do this. The first uses java’s Timer and TimerTask and the second android’s Handler. Both of them help in implementing the same algorithm:
- on every key stroke we first cancel any previous call request
- then we setup some kind of timer for our delay and the code that needs to be called
- and finally, when the time passes, we make the call
Timer and TimerTask
We can use Timer
to schedule the execution of a block of code after a given delay. The provided block must be a TimerTask
which will be added to a queue and when the time comes it will be executed in a background thread. This last part is very important since we cannot set anything UI related there. That’s why we use the Timer
just for the delay part and then we use the view’s Handler
to execute the actual code to the main thread:
Recommended when there is a need to do some intensive work before returning back to the main thread but besides that it could be an overkill. That’s why it might be better to use the view’s Handler
for both the delay and the execution.
Handler
The Handler
class packs the same functionality as the Timer
. We can use it to add a block of code (being added as a callback in a Message
instance) in a queue (the handler’s MessageQueue
) and when the time comes the message gets removed from the queue and its callback gets executed in the thread that the handler was created in. In our case, since we are using the view’s handler we can be sure that the execution will take place in the main thread.
The Handler
class provides methods for both adding and removing from the queue. So what we end up with is something like this:
One note about the counter
variable. For removing a particular message we need to identify it and to do that we can use what is called a token. When posting for delay, we also provide an id in the form of a counter so that we can request its deletion later on.
Debounce extension
Since we are in Kotlin land and to avoid having the above code duplicated with various global counters for identification we can create an extension function that will pack everything together and help us in having a reusable component and more readable code:
So our code ends up looking like this:
which is very similar to the original code but provides the debounce functionality!