我已为this和this中的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:编辑后的代码在片段中运行,如果它具有任何重要性。
答案 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()
的文档:
在所有待处理后将消息推送到消息队列的端 当前时间之前的消息