How to Update the Android GUI From a Timer

If you found this post via a Google search, chances are that your Android app just crashed after you added an innocent-looking timer. You probably got this error:

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

You may have also found people saying that you can’t use a timer to update the GUI. Seems odd, right? Why would Google make a timer and then not let you use it for hardly anything?

Well, those people are wrong. While you can’t update the GUI directly from your timer, you can do so with a few little tweaks.

The error above happens because Android doesn’t want other threads, such as your timer, messing with its GUI. So, what you need to do is politely ask Android to make the update for you. To do that, you need to add a handler and a runnable. Android will monitor the handler for a signal from your timer. When it gets the signal, it will run the code in the runnable. It sounds complicated, but it amounts to only a few lines of code.

First, move the code that updates the GUI out of your timer and into a runnable. A runnable is a mechanism where one thread can tell another thread to run a block of code. In this example, there is one line of code which sets the TextView tv to the value of the global variable i:

final Runnable myRunnable = new Runnable() {
   public void run() {
      tv.setText(String.valueOf(i));
   }
};

Creating a handler is very simple:

final Handler myHandler = new Handler();

And in the timer, we pass the runnable to the handler:

private void UpdateGUI() {
   i++;
   //tv.setText(String.valueOf(i)); //This causes a runtime error.
   myHandler.post(myRunnable);
}

As an example, I took the Android “Hello World” app, and modified it into a counter that updates once per second:

public class HelloActivity extends Activity {
   int i=0;
   TextView tv;
   final Handler myHandler = new Handler();

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);

      tv=(TextView) findViewById(R.id.tv1);

      Timer myTimer = new Timer();
      myTimer.schedule(new TimerTask() {
         @Override
         public void run() {UpdateGUI();}
      }, 0, 1000);

   }

   private void UpdateGUI() {
      i++;
      //tv.setText(String.valueOf(i));
      myHandler.post(myRunnable);
   }

   final Runnable myRunnable = new Runnable() {
      public void run() {
         tv.setText(String.valueOf(i));
      }
   };
}

Why does Android do this, while other operating systems do not? The fact is that none of the major operating systems have thread-safe GUI frameworks, and updating the GUI from a thread is a bad idea that can lead to difficult-to-trace bugs.

For example, suppose you have a thread that updates a text control on a window, and the user closes the window. Your thread may still be running, and cause an error when it tries to update the text control that no longer exists. It is possible to code around this problem, but it requires that your thread be constantly checking to see if the controls it wants to update still exist.

So, Android eliminates a whole class of bugs with its thread/GUI policy. And you will likely see more of this in the future. For example, the Xojo language adopted the Android policy for Cocoa builds in June 2013.

I use the code above in my BlubberPatrol weight-loss app. So, you can install that from the Google Play Store and see how well it works.

16 Responses to “How to Update the Android GUI From a Timer”

  1. Nithin says:

    Thanks for the post. Helped me complete my app :-)

  2. Nick says:

    Thanks for the post. It’s good…

  3. Zizi Gebru says:

    Nice post. Thanks a lot.

  4. glum says:

    great, thx !

  5. Markus says:

    Thanks! Made my day :)

  6. Vipin Prabhakaran says:

    Thanks a bunch! Helped me complete my code. :)

  7. Anatoliy says:

    Спасибо !!!

  8. MisterDev says:

    Thanks, helped a lot!!!

  9. Julian Martinez says:

    Thanks, helped a lot this using Timer task, i was using other method using a postDelay within the thread, but after a while seems that the other one blocked the main thread… this seems to be much more stable, thanx!! :)

  10. Rolf says:

    Thanks for your great example.

    I could giveup my workaround to repaint everthing permanently by using invalidate() inside the onDraw().
    Now refresh works as expected timer event based.

  11. chandradeo says:

    hi i have tried to run your code on android AVD
    emulator.When i run the application on emulator it gives unfortunately the application
    has stopped.I have not added any extra things on you code but just copeied in android project and ran it on emulator. Plz suggest what may be the problem.

  12. Devaraj says:

    It helped me lot:). I wasted two days before visiting your post.

  13. Jorge Espejo says:

    Great info!!!

    i was having a lot of problems loggin some data from my arduino and wifi. Now all is working perfect.

    Thanks you very much!!!!

  14. Jonathan says:

    Thanks man ! You saved my life ^^

  15. Alireza says:

    brief and complete, very nice. thanks.

  16. shu jin says:

    great!thanks!

Leave a Reply