Timer(Task) = bad! Do it the Android way: Use a Handler :)

Well, after programming a while for Android I got in touch with some things that are different from usual Java. I already mentioned that before, when I decided to start writing about my experiences with Android: Android & Memory (Leaks) ;)

This time I’d like to write a bit about Timer and TimerTask and why you shouldn’t use them…

While coding for a project I noticed that updating the gui out of a TimerTask didn’t work everytime and specially didn’t work good. Actually it basically never worked and at first I just couldn’t figure what was going on. I put some debugging stuff in the timers and everything seemed to be fine, as the debug messages appeared in the Log. Still: the gui wasn’t affected at all :oogle:
So I started with some research and found a lot of people with same effects but just few answers (kind of get used to that ^^). So after some time I found an article on Android Developers: Updating the UI from a Timer. The author is describing a kind of similar problem to mine but still not the same. Anyway, he’s also talking about “The Android way” which basically says: Timer(Tasks) are bad! Do it the Android way: Use a Handler :) Interesting idea so I gave it a try and now it works perfectly :mrgreen:
I also found some more sources reporting about better performance using handlers and stuff like that (I might look that up again and post some links).

As you can see in the code snippet, it’s pretty easy to go that way too:

First we need a Handler that starts the Runnable after 100ms

private Handler handler = new Handler();
handler.postDelayed(runnable, 100);

And we also need the Runnable for the Handler

private Runnable runnable = new Runnable() {
   @Override
   public void run() {
      /* do what you need to do */
      foobar();
      /* and here comes the "trick" */
      handler.postDelayed(this, 100);
   }
};

So the “trick” is to tell the handler at the end to start the Runnable again. This way the runnable is started every 100ms, like a scheduleAtFixedRate() TimerTask! If you want it to stop, you can just call handler.removeCallback(runnable) and it won’t start again, until you tell it to :thumbup:
There’s also another advantage of this solution: You don’t have to create new Timer(Task)s all the time and can reuse the one Handler and Runnable.

By the way, to get notified about new posts, just enter your email address on the right :)

49 comments

  • Thanks a lot for sharing this!

    I was spending hours looking for why my Timer wouldn’t update my GUI, even though I saw that it would run the code if I had set a breakpoint. This worked great, and was a simple solution.

    There is an error in your code though, as the handler is named “mHandler” on your second row (should just be “handler”).

  • Oh thanks for the hint :)

  • How do you reset the timer to 0? When a button is clicked I want the “timer” (a textview wtih 00:00:00) to reset to just that “00:00:00”. Right now I get the value last stopped at, which seems correct, but is not the full solution I need.

    Ideas?

    Thanks for such in advance.

  • I don’t really understand your problem. Can you explain it in more detail and maybe post some code?

  • Good morning, i have a question: what is “foobar ()”?

  • Well, i have to thank you for your advice.

    After lots of troubles with TimerTask, Handler saved me from headaches!

  • i want to call a mthod in a given time interval. eg. in every 10 minutes, how can i do that?

  • I’ve tried to stop it with the call below, but it’s still running. Do you know why?
    handler.removeCallbacks(runnable);

  • Thanks!!!
    So easy and just what I want!

    pd. to stop it, its handler.removeCallbacks(runnable); // end ‘s’ missing

  • the code was helpful, nice way to get rid of timertasks. But i have a problem
    My Handler doesnt get stopped even after calling the handler.removeCallbacks(runnable); method.

    I am using a toggle switch to Start and Stop the handler. But even after calling the removeCallbacks() methos the handler continues to hit my Webservice in background. Please help me here. I will paste part of my code here.

    /********************/
    if (toggleStoreAlert.isChecked()) {

    Log.d(“BDZ”, “**** Store Alert Timer ON***”);
    /* Post the HANDLER to Start here */
    handler.postDelayed(runnable, 5000);

    } else {
    /*
    * Cancel the Timer here if the User Toggles the Switch
    */
    handler.removeCallbacks(runnable);
    Log.d(“BDZ”, “**** Store Alert Timer OFF ***”);
    }
    /********************/

    and my Runnable is as below

    /****************/
    private Runnable runnable = new Runnable() {
    @Override
    public void run() {

    /* I Hit My WS in this following method*/
    getStoreAlertData();

    Log.d(“BDZ”, “**** Store Alert Timer ReStarted***”);
    handler.postDelayed(this, 5000);
    }
    };
    /****************/

  • Your timer works great…till Android tosses my entire app out after a period of inactivity. I want to avoid having the app tossed out since it is receiving SMS messages outside the UI string. Is there a way to keep it alive?

  • Hey Peter, I didn’t do any Android development for some time but it sounds like you should use a service in your case. Services usually aren’t killed but keep running in the background.

  • Hey anything from my code. Why the timer keeps running in the Background, even if i close the app.

  • Thank you much!

  • This was really helpful. I found this page after trying to set text in my fragment using a timer in the fragment and then trying to set it from an activity. This approach is the lightest and the cleanest.
    If you are using this in the fragment, keep the new Handler() and the postDelayed(runnable,500) part in the onCreate method.
    Thank you!

  • Use runOnUiThread for using timer. Timer is build based on thread. It is a standard approach made by java to handle task. Android may be different than java, but in the end it is all handled by java. So I would preffer you use Timer’s scheduleOnTimerTask and control your timer yourself.

  • I am able to stop a timer and a task using following code:

    if(null != timer)
    {

    timer.cancel();
    Log.i(LOG_TAG,”Number of cancelled tasks purged: ” + timer.purge());
    timer = null;
    }

    if(task != null)
    {
    Log.i(LOG_TAG,”Tracking cancellation status: ” + task.cancel());
    task = null;
    }

  • The problem I was having when using the timer approach was when I press the button and shut the screen down. Even though I call cancel() in onPause() things were not cleaned up well. When I hit the button again and the phone comes back on the activity should start running again but it would blow up with a timer cancelled error which tells me the timer was not getting cleaned up when the screens were torn down. Using the Runnable approach there are no issues I can find any more.

  • “… like a scheduleAtFixedRate() TimerTask!”
    Actually the handler isn’t a scheduleAtFixedRate() TimerTask! Schedule at fixed rate means that the timer trys to run your TimerTask exactly every given period. But the handler can get a delay. For example, if your foobar() (in your example) needs 100ms to execute and after these 100ms you call handler.postDelayed(this, 100), the next handler-run-call will be executed in 200ms, not 100ms!
    scheduleAtFixedRate() trys to compensate these delays.

  • Wonderful. It was very helpful for my.

    Thanks a lot!!!

  • This helped me but I still have a problem. When I call handler.removeCallbacks(runnable) program stops there and other buttons can’t be operated. Looks like program freeze at this point and I can’t use program unless I restart it. Do you have any suggestions how to fix this?

  • FYI
    Getting NetworkOnMainThreadException inside a runnable, when targeting 3.0+ because postDelayed does not run the Runnable on a background thread!
    I need to had an ASyncTask inside the handler and it works

  • Thanks for this!!

  • Would you post the code that did not work?

  • Hi, Im trying to do the similar. I want the runnable to execute only once after ten seconds.
    I have given this code in the onCreateView of my fragment. This is working well. But runnable is executing twice. I couldn’t find why its happening. Can you please help me.

    runnable = new Runnable() {
    @Override
    public void run() {
    JLogger.getInstance(context).log(“INSIDE RUNNABLE”);
    doneBtn.performClick();
    }
    };

    handler = new Handler();

    handler.postDelayed(runnable,10000);

    doneBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    if(!isBack){
    isBack = true;
    JLogger.getInstance(context).log(“INSIDE CLICK”);
    getToHome();
    }

    }
    });

  • I’m not sure what you’re trying to do but why don’t you just call the getToHome(); inside the runnable?

  • Awesome…Far better and cleaner way than Timer Task

  • Thanks for this example, I was about to explore the use a timer, when I stumbled across this.

  • Thanks for sharing this! Works like a charme :-)

  • I have read above tutorial and i have to try to use my app.

  • Good article, very easy and practical to implement. Thank You Moritz!

  • Thank you so much for this article. The Timer class was crashing out my application, but using the handler class everything worked perfectly the first time.

    Thanks again.

  • I don’t know how to thank You, this article is really helpful.

  • Really thankful for this article. Helps a lot!!! Thank you so much!

  • Works great!!!! Thank You Moritz!

  • ConcernedAndroid

    Hey mate!

    Thanks for sharing your thoughts, however I must say that you premise(timer task is bad) is faulty at least in some way. Handlers fit your usage perfectly however if you were to consider invoking methods not interacting with GUI on a delayed or fixed rate base timer task could do miracles and not affect memory all that much.

    Once again thank for sharing! Cheers

  • How would you rate android.os.CountDownTimer in this regard ?

  • I’m sorry but I didn’t program for Android for a while so I don’t have an opinion on that.

  • Timer(task) is not bad, you’re just using it wrongly.

    If you do the same on Windows it will also generate an exception if it does not execute on main thread. As on Windows you must run your updating UI code on the main thread, on Android you do it with Activity.RunOnUIThread, just surround your code with it and it will work.

    Cheers

  • Hi Gusman,
    you might be right for current versions of Android. I don’t know about it as I haven’t programmed for Android for a while.
    But with the versions back in 2010, when this post was published, you’re probably wrong. That’s also why there was an article on the Android Developers Page about it (I linked it up there and you can find it on archive.org[1]). Back in the days one had to find and use a bunch of workarounds for different problems, which weren’t solved by the API and this one worked perfectly :)
    Cheers

    [1] https://web.archive.org/web/20100126090836/http://developer.android.com/intl/zh-TW/resources/articles/timed-ui-updates.html

  • RunOnUIThread exists since api level version 1, so it applies from the beginning of Android (I’m using Android + Xamarin since Android 2.0 and I always have used this)…

    Cheers.

  • I didn’t know about that one but if it works as intended and expected, it’s definitely worth trying!
    Nevertheless, Google itself published the mentioned workaround as best practice on their developers page. I guess they also had a reason for that :)

  • Hey, and thank you so much! I was searching for a solution to use as timer that won’t cause any problems and just works flawlessly but couldn’t find any. The ones that I found where just so complicated and did still not really give me the right solution. You just gave me the perfect solution for my problem and it’s so simple actually :D thank you really much, really enjoy people who know what they’re doing and know how to teach others ^^

  • Great article man just one one thing. handler.removeCallbacks(runnable) Callbacks is missing the ‘s’ on the end in your article ;)

  • Hey Moritz,

    private Handler handler = new Handler();
    handler.postDelayed(runnable, 100);

    In the second row 2 Errors:
    Syntax error on token “(“, delete this token
    Syntax error on tokens, VariableDeclarator expected instead
    ?
    Martin

  • Hi Martin, are you sure you copied the code correctly?

  • thank you soooo much.

  • sorry but my expandable view repeated with handler…..but with timmer it will fine

Leave a Reply