简体   繁体   中英

Resuming CountdownTimer after rotation

I have a CountdownTimer that counts down from 60 seconds. This CountdownTimer works by setting a textView to the remaining milliseconds, but whenever i rotate my device, the CountdownTimer gets reset.

I know this happens because the Activity gets restarted on rotation. So i tried saving the time remaining in a bundle and then restoring it, after the Activity was restarted.

long transferValue;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_playtimemode);

    Log.d("Debug", "onCreate: " + transferValue);

    long setTime = 60000;
    long difference = setTime - transferValue;

    new CountDownTimer(difference, 1000) {

        public void onTick(long millisUntilFinished) {
            millisUntilFinishedToSave = millisUntilFinished;
            tvCountdown.setText("" + millisUntilFinished / 1000);
        }

        public void onFinish() {
            tvCountdown.setText("done!");
        }
    }.start();

}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putLong("millisKey", millisUntilFinishedToSave);

}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    transferValue = savedInstanceState.getLong("millisKey");
    Log.d("Debug", "onRestoreInstanceState(): " + transferValue);
}

This however doesn't work. I am intializing transferValue at the top of this code (hence it returning 0), but how can i else save the data from the savedInstanceState to the CountdownTimer?

07-06 20:21:30.038: D/Debug(28995): onCreate: 0
07-06 20:21:30.043: D/Debug(28995): onRestoreInstanceState(): 55994

I would give your timer it's own thread. Your timer is being stopped because it's on the UI thread (as you stated) and when the UI redraws the Activity is re-initialized. All long running processes should have their own thread. Rule of thumb: get out of the UI thread as soon as possible.

Here is an example of using a Service. This service will start when called and stay in memory regardless of screen orientation changes or even activity focus changes.

Here is the service:

public class Timer extends Service {

    @Override
    public IBinder onBind(Intent i) {
        return null;
    }
    @Override
    public int onStartCommand(Intent i, int flags, int startId) {
        // Put your timer code here
    }
}

You will need to add this line to your manifest (somewhere between the application open/close tags):

<service android:name=".Timer" />

Then you can start the service at any time by using this (it's important to note that you can start it over and over again, the recursive calls do not make a new service.):

startService(new Intent(this, Timer.class));

Use System.currentTimeMillis to get the current system time, then add 60000 milliseconds to the time and store that as an end time. Then any time you have to change anything, just compare System.currentTimeMillis to the EndTime.

Endtime = System.currentTimeMillis + 60000;

then on every instance

TimeRemaining = Endtime - System.currentTimeMillis

The accepted answer makes the thing very complex. You can do it in a simpler way. The problem in your code is that Activity gets created on rotation (see Activity Lifecycle), so does the CountdownTimer instance.

I could write the whole example code but there is a nice answer from @Drew here: Android Innerclass TextView reference when activity resumes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM