Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: TimerTask scheduled for repetition getting fired only once

Ok this is a very weird problem I am having, and I'm pretty sure that I am messing up somewhere, but I can't quite figure out where.

What I am trying is -

  • Schedule a Timer to execute a TimerTask every five seconds
  • The TimerTask in turn executes an AsyncTask (which in this case simple sleeps for a second before returning the static count of the number of AsyncTasks).
  • Finally, the aforementioned count is updated in the UI.

And of course, the appropriate Handlers and Runnables have been used to post asynchronous messages from other threads to the UI.

This code executes only once. I expect it to fire every 5 seconds. Here's the code.

Note: I had no idea what to do with the Looper. I put it there after trial and error!

public class TimerAsyncMixActivity extends Activity {
    public static final String TAG = "TimerAsyncMix";
    static int executionCount = 0;
    Handler mHandler = new Handler();

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

        new Timer().schedule(new MyTimerTask(this), 0, 5000);
    }

    class MyAsyncTask extends AsyncTask<String, Void, Integer>{
        @Override
        protected Integer doInBackground(String... params) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return ++executionCount;
        }

        @Override
        protected void onPostExecute(Integer result) {

            mHandler.post(new UpdateUiThread(TimerAsyncMixActivity.this, result));
            super.onPostExecute(result);
        }
    }
}



class MyTimerTask extends TimerTask{
    private TimerAsyncMixActivity tma;

    public MyTimerTask(TimerAsyncMixActivity tma) {
        this.tma = tma;
    }

    @Override
    public void run() {
        Looper.prepare();
        Log.d(TimerAsyncMixActivity.TAG, "Timer task fired");
        tma.new MyAsyncTask().execute();
        Looper.loop();
        Looper.myLooper().quit();
    }
}

class UpdateUiThread implements Runnable{

    int displayCount;
    TimerAsyncMixActivity tma;
    public UpdateUiThread(TimerAsyncMixActivity tma, int i) {
        this.displayCount = i;
        this.tma = tma;
    }

    @Override
    public void run() {
        TextView tv = (TextView) tma.findViewById(R.id.tvDisplay);
        tv.setText("Execution count is : "+displayCount);
    }

Can anyone point me to what I'm doing wrong?

like image 702
curioustechizen Avatar asked Jul 11 '11 15:07

curioustechizen


People also ask

What is the difference between Android timer and a handler to do action every n seconds?

Handler is better than TimerTask . The Java TimerTask and the Android Handler both allow you to schedule delayed and repeated tasks on background threads. However, the literature overwhelmingly recommends using Handler over TimerTask in Android (see here, here, here, here, here, and here).

Is TimerTask a thread?

Both TimerTask and Thread execute asynchronously, but TimerTask is scheduled to execute at fixed intervals while Thread is not.

Is Timer thread safe java?

Java Timer class is thread safe and multiple threads can share a single Timer object without need for external synchronization. Timer class uses java. util.


2 Answers

techie, this is how I implemented similar things. I'm won't claim that this is the best way, but it has worked for me and doesn't look too bad.

I have the following code in my activity. I create an async task when the activity starts and I stop it onPause. The AsyncTask does whatever it needs to do, and updates the UI on onProgressUpdate() (which is run on the UI thread, so there's no need to use a Handler).

private Task task;
@Override
protected void onPause() {
    task.stop();
    task = null;
}

@Override
protected void onResume() {
    task = new Task();
    task.execute();
}

private class Task extends AsyncTask<Void, String, Void> {

    private boolean running = true;
    @Override
    protected Void doInBackground(Void... params) {
        while( running ) {
            //fetch data from server;
            this.publishProgress("updated json");
            Thread.sleep(5000); // removed try/catch for readability
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(String... values) {
        if( ! running ) {
            return; 
        }
        String json = values[0];
        //update views directly, as this is run on the UI thread. 
        //textView.setText(json);
    }

    public void stop() {
        running = false;
    }
}
like image 146
Augusto Avatar answered Sep 21 '22 13:09

Augusto


Do not use a timer. If your phone goes to sleep, the timer is suspended too. Use AlarmManager.

like image 20
Plamen Nikolov Avatar answered Sep 21 '22 13:09

Plamen Nikolov