CountDownTimer onTick()只被调用一次

时间:2018-04-04 00:20:26

标签: android countdowntimer

我已为thisthis中的Android应用构建了一个自定义CountDownTimer,以添加功能(暂停等)并使其比原始CountDownTimer更准确。

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


public abstract class MoreAccurateCountDownTimer {

    /**
     * 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;

    /**
    * boolean representing if the timer was cancelled
    */
    private boolean mCancelled = false;

    private boolean mPaused = false;


    private long mNextTime;

    /**
     * @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 MoreAccurateCountDownTimer(long millisInFuture, long countDownInterval) {
        mMillisInFuture = millisInFuture;
        mCountdownInterval = countDownInterval;
    }

    /**
     * Cancel the countdown.
     */
    public synchronized final void cancel() {
        mCancelled = true;
        mHandler.removeMessages(MSG);
    }

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

        mNextTime += mCountdownInterval;
        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG), mNextTime);
        return this;
    }

    public long pause() {
        mPauseTime = mStopTimeInFuture - SystemClock.elapsedRealtime();
        mPaused = true;
        return mPauseTime;
    }

    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 (MoreAccurateCountDownTimer.this) {
                if (mCancelled) {
                    return;
                }

                if (!mPaused) {
                    final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
                    if (millisLeft <= 0) {
                        onFinish();
                    } else {
                        onTick(millisLeft);

                        long currentTime = SystemClock.elapsedRealtime();
                        do {
                            mNextTime += mCountdownInterval;
                        } while (currentTime > mNextTime);

                        if (mNextTime < mStopTimeInFuture) {
                            sendMessageAtTime(obtainMessage(MSG), mNextTime);
                        } else {
                            sendMessageAtTime(obtainMessage(MSG), mStopTimeInFuture);
                        }

                    }
                }
            }
        }
    };
}

Timer每秒都会更新一个Text和一个ProgressBar(倒计时,谁会想到:))并且可以通过一个按钮(FAB)启动,暂停和恢复。 所有这些都适用于多个仿真器,并且它在我的旧手机(Nexus 5)上运行了一段时间(一种正在进行的侧面项目)。 现在我在我的新手机(Pixel 2)上进行了测试,但它无法正常工作 似乎每次&#34;动作&#34;只调用onTick()一次。 (开始,暂停,恢复),这导致:(示例) - &gt;我按开始,等待5秒,按暂停(直到现在没有任何事情发生),然后恢复。在简历上单击它会使用-5秒更新Text和ProgressBar,并且不会再进行任何操作(视觉上) 这里有一个非常奇怪的部分:当我重新启动手机然后在做任何其他事情之前打开应用程序时,它会起作用!如果我把它放在一边几分钟后(屏幕关闭)它再次被窃听。

到目前为止我的想法:
- 计时器本身(处理程序)似乎工作,因为当它在恢复点击时更新UI时,丢失的秒数对应于实际秒数:P
- 我把整个班级的日志放在班级上,检查是否有东西没有在那里被调用,但一切都是(每次点击只需一次,而不是它本身就应该这样)。
- 我在模拟器中模拟了空闲/深度睡眠,因为我认为它可以解释为什么它在重启后工作。它没有 - 我试着一步一步地调试它,但没有什么突出的我 - Android Studio不会向我显示任何错误,异常等。

也许我只是对一个明显的错误视而不见,因为我看了很多(我希望),我真的希望有人立刻看到它:) 任何帮助深表感谢!

编辑以澄清:
在我的FAB的onClick()中,我呼叫countDownTimer1.start();或暂停/恢复 而onTick()部分看起来像这样:

MoreAccurateCountDownTimer countDownTimer1 = new MoreAccurateCountDownTimer(timeTimer * 1000 + 100, 1000) {
    @Override
    public void onTick(long millisUntilFinished) {
        timeRemaining.setText(...etc...);
                progressCircle1.setProgress((int) (millisUntilFinished / 1000));

onFinish()会以同样的方式调用第二个计时器 小编辑2:编辑后的代码在片段中运行,如果它具有任何重要性。

1 个答案:

答案 0 :(得分:0)

<强>更新 基于sendMessageAtTime()的{​​{1}}:

  

在绝对时间(以毫秒为单位)uptimeMillis之前,所有待处理消息之后将消息排入消息队列。 时基isuptimeMillis()。深度睡眠所花费的时间会给执行带来额外的延迟。

当我改变你所有的

SystemClock.elapsedRealtime()

SystemClock.uptimeMillis()

并且,在onResume()中执行以下操作:

mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG))

intead of

mHandler.sendMessage(mHandler.obtainMessage(MSG));

完美无缺。基于handler.sendMessage()的文档:

  

在所有待处理后将消息推送到消息队列的   当前时间之前的消息