Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android timer/timertask causing my app to crash?

Just testing out a simple block of code in my mainActivity's onCreate:

Timer timer2 = new Timer(); 
        TimerTask testing = new TimerTask() {
            public void run() { 
                Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();

            }
        };
        timer2.schedule(testing, 1000);

I get the "force close" error though.

What gives?

like image 976
JDS Avatar asked Jun 11 '11 04:06

JDS


4 Answers

Alright for anyone else who runs into this, I fixed the problem by using a Handler and Runnable to do the Toast, which seems to be needed for UI interaction:

    final Handler handler = new Handler(); 
    Timer timer2 = new Timer(); 
    TimerTask testing = new TimerTask() {
        public void run() { 
            handler.post(new Runnable() {
                public void run() {
                    Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();
                }

            });


        }
    };
    timer2.schedule(testing, 1000);

I still don't understand why this is necessary though, perhaps someone could explain? But hey at least this code works lol.

like image 117
JDS Avatar answered Nov 10 '22 23:11

JDS


Timer(Tasks) are bad! Do it the Android way: Use a Handler.

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

like image 3
waqas ali Avatar answered Nov 10 '22 23:11

waqas ali


This exact issue is discussed in this article:

http://developer.android.com/resources/articles/timed-ui-updates.html

like image 1
Paul Butcher Avatar answered Nov 10 '22 23:11

Paul Butcher


The app crashes because you are attempting to access elements of the UI thread (a toast) from a different thread (the timer thread). You cannot do this!

You can get round it by either:

Sending a handler message from the timer thread to the UI thread, and then showing the toast in the UI handler function.

OR

In the timer code run use 'runOnUiThread':

@Override

public void run() 

{

    mainActivity.runOnUiThread(new Runnable() {

        public void run() {

            // Access/update UI here

            Toast.makeText(mainActivity.this, "test", Toast.LENGTH_SHORT).show();

        }

    });

}
like image 1
rockhead006 Avatar answered Nov 10 '22 21:11

rockhead006