开发者

Pause CountDownTimer in Android when activity is not in front

I have an activity that uses a CountDownTimer that counts down from 10. How do I pause that timer when the activity is no longer in focus, like if the user get a call or something, then resume the timer when the user goes back to the activity? Is this even possible开发者_如何学Go?


I would add something to the onTick handler to save the progress of the timer in your class (number of milliseconds left).

In the onPause() method for the activity call cancel() on the timer.

In the onResume() method for the activity create a new timer with the saved number of milliseconds left.


You can use pause() to pause the timer and later on Start or Resume the countDownTimer by calling start().

/**
 * This class uses the native CountDownTimer to 
 * create a timer which could be paused and then
 * started again from the previous point. You can 
 * provide implementation for onTick() and onFinish()
 * then use it in your projects.
 */
public abstract class CountDownTimerPausable {
    long millisInFuture = 0;
    long countDownInterval = 0;
    long millisRemaining =  0;

    CountDownTimer countDownTimer = null;

    boolean isPaused = true;

    public CountDownTimerPausable(long millisInFuture, long countDownInterval) {
        super();
        this.millisInFuture = millisInFuture;
        this.countDownInterval = countDownInterval;
        this.millisRemaining = this.millisInFuture;
    }
    private void createCountDownTimer(){
        countDownTimer = new CountDownTimer(millisRemaining,countDownInterval) {

            @Override
            public void onTick(long millisUntilFinished) {
                millisRemaining = millisUntilFinished;
                CountDownTimerPausable.this.onTick(millisUntilFinished);

            }

            @Override
            public void onFinish() {
                CountDownTimerPausable.this.onFinish();

            }
        };
    }
    /**
     * Callback fired on regular interval.
     * 
     * @param millisUntilFinished The amount of time until finished. 
     */
    public abstract void onTick(long millisUntilFinished);
    /**
     * Callback fired when the time is up. 
     */
    public abstract void onFinish();
    /**
     * Cancel the countdown.
     */
    public final void cancel(){
        if(countDownTimer!=null){
            countDownTimer.cancel();
        }
        this.millisRemaining = 0;
    }
    /**
     * Start or Resume the countdown. 
     * @return CountDownTimerPausable current instance
     */
    public synchronized final CountDownTimerPausable start(){
        if(isPaused){
            createCountDownTimer();
            countDownTimer.start();
            isPaused = false;
        }
        return this;
    }
    /**
     * Pauses the CountDownTimerPausable, so it could be resumed(start)
     * later from the same point where it was paused.
     */
    public void pause()throws IllegalStateException{
        if(isPaused==false){
            countDownTimer.cancel();
        } else{
            throw new IllegalStateException("CountDownTimerPausable is already in pause state, start counter before pausing it.");
        }
        isPaused = true;
    }
    public boolean isPaused() {
        return isPaused;
    }
}


No need to create a new Timer, just set the millisUntilFinished = total. For instance

private CountDownTimer cdTimer;
private long total = 30000;

        ...
        toggleButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view){
                if(toggleButton.isChecked()) {
                    startCountDownTimer();
                }else{
                    cdTimer.cancel();
                }
            }
        });
        ...

    private void startCountDownTimer() {
        cdTimer = new CountDownTimer(total, 1000) {
            public void onTick(long millisUntilFinished) {
                //update total with the remaining time left
                total = millisUntilFinished;
                nTimeLabel.setText("seconds remaining: " +  millisUntilFinished/ 1000);
            }
            public void onFinish() {
                nTimeLabel.setText("done!");
            }
        }.start();
    }


This must be exactly what you're looking for. Source is this Gist.

package alt.android.os;

import android.os.Handler;
import android.os.SystemClock;
import android.os.Message;

public abstract class CountDownTimer {

/**
 * Millis since epoch when alarm should stop.
 */
private final long mMillisInFuture;

/**
 * The interval in millis that the user receives callbacks
 */
private final long mCountdownInterval;

private long mStopTimeInFuture;

private long mPauseTime;

private boolean mCancelled = false;

private boolean mPaused = false;

/**
 * @param millisInFuture The number of millis in the future from the call
 *   to {@link #start()} until the countdown is done and {@link #onFinish()}
 *   is called.
 * @param countDownInterval The interval along the way to receive
 *   {@link #onTick(long)} callbacks.
 */
public CountDownTimer(long millisInFuture, long countDownInterval) {
    mMillisInFuture = millisInFuture;
    mCountdownInterval = countDownInterval;
}

/**
 * Cancel the countdown.
 *
 * Do not call it from inside CountDownTimer threads
 */
public final void cancel() {
    mHandler.removeMessages(MSG);
    mCancelled = true;
}

/**
 * Start the countdown.
 */
public synchronized final CountDownTimer start() {
    if (mMillisInFuture <= 0) {
        onFinish();
        return this;
    }
    mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
    mHandler.sendMessage(mHandler.obtainMessage(MSG));
    mCancelled = false;
    mPaused = false;
    return this;
}

/**
 * Pause the countdown.
 */
public long pause() {
    mPauseTime = mStopTimeInFuture - SystemClock.elapsedRealtime();
    mPaused = true;
    return mPauseTime;
}

/**
 * Resume the countdown.
 */
public long resume() {
    mStopTimeInFuture = mPauseTime + SystemClock.elapsedRealtime();
    mPaused = false;
    mHandler.sendMessage(mHandler.obtainMessage(MSG));
    return mPauseTime;
}

/**
 * Callback fired on regular interval.
 * @param millisUntilFinished The amount of time until finished.
 */
public abstract void onTick(long millisUntilFinished);

/**
 * Callback fired when the time is up.
 */
public abstract void onFinish();


private static final int MSG = 1;


// handles counting down
private Handler mHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {

        synchronized (CountDownTimer.this) {
            if (!mPaused) {
                final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

                if (millisLeft <= 0) {
                    onFinish();
                } else if (millisLeft < mCountdownInterval) {
                    // no tick, just delay until done
                    sendMessageDelayed(obtainMessage(MSG), millisLeft);
                } else {
                    long lastTickStart = SystemClock.elapsedRealtime();
                    onTick(millisLeft);

                    // take into account user's onTick taking time to execute
                    long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();

                    // special case: user's onTick took more than interval to
                    // complete, skip to next interval
                    while (delay < 0) delay += mCountdownInterval;

                    if (!mCancelled) {
                        sendMessageDelayed(obtainMessage(MSG), delay);
                    }
                }
            }
        }
    }
};
}


You can try using Hourglass

Hourglass hourglass = new Hourglass(50000, 1000) {
        @Override
        public void onTimerTick(long timeRemaining) {
            // Update UI
            Toast.show(MainActivity.this, String.valueOf(timeRemaining), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onTimerFinish() {
            // Timer finished
            Toast.show(MainActivity.this, "Timer finished", Toast.LENGTH_SHORT).show();


        }
    };

Use hourglass.startTimer(); to start the timer.

It has helper methods which allow to pause and resume the timer.

hourglass.pauseTimer();

AND

hourglass.resumeTimer();


Here is the code below .Use it in your activities it works fine.

public class MainActivity extends AppCompatActivity {

    TextView textview;
    final static long INTERVAL = 1000;
    final static long TIMEOUT = 11000;
    static long millisecondsleft;
    boolean isPause =false;

    CountDownTimer countDownTimer;
    CountDownTimer countDownTimeronResume;

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

        textview=findViewById(R.id.textviewcheck);
 }

    @Override
    protected void onResume() {
        super.onResume();

       if(isPause == false) {
           countDownTimer = new CountDownTimer(TIMEOUT, INTERVAL) {
               @Override
               public void onTick(long millisUntilFinished) {
                   millisecondsleft = millisUntilFinished;
                   textview.setText(":" + String.format("%02d", millisUntilFinished / 1000));
               }

               @Override
               public void onFinish() {

                   textview.setText("DONE!");
               }
           }.start();

       } else{
                     countDownTimeronResume = new CountDownTimer(millisecondsleft, INTERVAL) {
                       @Override
                       public void onTick(long millisUntilFinished) {
                           Toast.makeText(MainActivity.this, "ONPAUSED", Toast.LENGTH_SHORT).show();
                           millisecondsleft = millisUntilFinished;
                           textview.setText(":" + String.format("%02d", millisUntilFinished / 1000));
                       }

                       @Override
                       public void onFinish() {
                           textview.setText("DONE!");

                       }
                   }.start();
         }


    }

    @Override
    protected void onPause() {
        super.onPause();

        if(countDownTimer!=null){
            countDownTimer.cancel();
            isPause = true;
        }
       if(countDownTimeronResume!=null){
            countDownTimeronResume.cancel();
       }
    }
}


For Kotlin user, checkout this

For eg:

// Init timer
lateinit var timerExt: CountDownTimerExt

timerExt = object : CountDownTimerExt(TIMER_DURATION, TIMER_INTERVAL) {
    override fun onTimerTick(millisUntilFinished: Long) {
        Log.d("MainActivity", "onTimerTick $millisUntilFinished")
    }

    override fun onTimerFinish() {
        Log.d("MainActivity", "onTimerFinish")
    }

}

// Start/Resume timer
timerExt.start()

// Pause timer
timerExt.pause()

// Restart timer
timerExt.restart()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜