2

For an Android Activity, how do I stop or pause a thread on onStop(), and then restart or unpause the thread on onRestart()? When I start another activity on my phone, it looks like onStop() properly stops my thread, but when I try to restart my activity, onRestart() does not work as intended and the thread is no longer running, i.e., my views are no longer refreshing and the countdown is frozen. (Rotating my phone seems to restart the thread, i.e., the views resume refreshing and the countdown is active.)

Also, is it better that onStop() stops your thread, or should it only pause it?

public class MyActivity extends Activity {

    private static final int SLEEP_TIME = 500;  
    private RefreshingThread refreshingThread = new RefreshingThread();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        refreshingThread.start();
    }

    @Override
    protected void onStop(){
        super.onStop();
        refreshingThread.pause();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        refreshingThread.unpause();
    }

    private void updateViews() {
    // code to update my Views, including refreshing a countdown        
    }

    class RefreshingThread extends Thread {

        private volatile boolean isPaused = false;

        @Override
        public void run() {
            try {
                while (!isInterrupted() && !isPaused) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                             updateViews();
                        }
                    });
                    Thread.sleep(SLEEP_TIME);
                }
            } catch (InterruptedException e) {
                Log.w("MyActivity", "Caught InterruptedException", e);
            }
        }

        public void pause() {
            isPaused = true;
        }

        public void unpause() {
            isPaused = false;
        }

    }
}
anomal
  • 2,249
  • 2
  • 19
  • 17
  • did you test your code in `OnResume();` instead of `OnRestart()`? – Shayan Pourvatan Jan 01 '14 at 06:10
  • @Shayanpourvatan I have a countdown, so I don't want to stop the countdown during `onPause()`. – anomal Jan 01 '14 at 06:15
  • I said put `refreshingThread.unpause();` into `OnResume();`,did you test that? – Shayan Pourvatan Jan 01 '14 at 06:19
  • 1
    I highly recommend you read about Activity's life cycle:http://developer.android.com/reference/android/app/Activity.html. – Lior Ohana Jan 01 '14 at 06:24
  • @Shayanpourvatan I tried adding `refreshingThread().unpause()` into `onResume()` just now, and the behaviour is the same. – anomal Jan 01 '14 at 06:24
  • Have you tested to see if the Thread is running after unPause() in the debugger, is the Thread not running or just views not updating? – Steve M Jan 01 '14 at 06:25
  • I think this is a near duplicate of http://stackoverflow.com/questions/6776327/how-to-pause-resume-thread-in-android – Steve M Jan 01 '14 at 06:30
  • @svenoaks From the logs, the Thread state is TERMINATED after unpause(). – anomal Jan 01 '14 at 06:34
  • @anomal Please review Java threads. As soon as you fall through your while loop in RefreshingThread your thread is done. Note that in svenokas link the answer has two nested loops within the runnable part of the thread. – Morrison Chang Jan 01 '14 at 07:09

3 Answers3

1

First, it is advised that refreshing data will be done by pushing new data from the server rather than pulling it - this will help saving battery, bandwidth and being more efficient in general. you can use GCM to push data, for example check: http://www.doubleencore.com/2013/09/push-dont-poll-how-to-use-gcm-to-update-app-data/

If you still prefer pulling data once every X seconds (SLEEP_TIME), I would suggest you'll use a Timer, which can be scheduled to run a TimerTask every X seconds. you can then cancel/restart it from onPause/onResume. Example:

public class RefreshManager {
    private static Timer timer = null;
    private RefreshTimerTask refreshTask;

    public void onResume() {
        this.start(INIT_DELAY_TIME);
    }

    public void onPause() {
        this.stop();
    }

    private void start(long delay) {
        stop(); // stop any older timer instance if exist.
        timer = new Timer();
        refreshTask = new RefreshTimerTask();
        timer.schedule(refreshTask, delay, SLEEP_TIME);
    }

    private void stop() {
        if (timer != null) {
            timer.cancel();
            refreshTask = null;
            timer = null;
        }
    }

    private class RefreshTimerTask extends TimerTask {
        @Override
        public void run() {
            updateViews();
        }
    }
}

You should create a RefreshManager instance and call it's onResume and onPause on the activity onPause/onResume.

0

Change this method:

@Override
protected void onRestart() {
    super.onRestart();
    refreshingThread.unpause();
}

To:

@Override
protected void onStart() {
    super.onStart();
    refreshingThread.start();   <-- remove from onCreate();
}

With this you will always start the thread when your activity starts up (or restarts) and stop it when your Activity is stopped.

Rick Falck
  • 1,778
  • 3
  • 15
  • 19
  • That causes the app to crash when I restart the activity. `01-01 07:54:50.879: E/AndroidRuntime(26303): java.lang.RuntimeException: Unable to resume activity {anomal.myapp/anomal.myapp.MyActivity}: java.lang.IllegalThreadStateException: Thread already started.` – anomal Jan 01 '14 at 12:58
0

I got it to work. I renamed my thread's pause() method to shouldStop(). I created a new thread each time in onStart(), while calling my thread's shouldStop() method each time in onStop().

private RefreshingThread refreshingThread = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
protected void onStart(){
    super.onStart();
    refreshingThread = new RefreshingThread();
    refreshingThread.start();       
}  

@Override
protected void onStop(){
    super.onStop();
    refreshingThread.shouldStop(); 
}
anomal
  • 2,249
  • 2
  • 19
  • 17