我正在尝试构建某种顺序倒计时。意思是,我建立了一个“练习”队列,每个练习都包含一个特定的持续时间,即倒计时时间。在自定义的Countdown类中,我将这些练习从队列中弹出并将持续时间用作倒计时。
我希望这些倒计时一个接一个地运行。为此,我根据抽象类CountDownTimer
的代码基础构建了一个Countdown类。
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Locale;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.widget.Button;
import android.widget.TextView;
public class ExerciseMeCountDownTimer {
private static final int MSG_COUNTDOWN = 100;
private static final int MSG_FINISH = 99;
private ArrayDeque<Exercise> eq;
private long mMillisInFuture;
private int mCountdownInterval;
private String name;
private long mStopTimeInFuture;
CountdownHandler cHandler;
public ExerciseMeCountDownTimer(ArrayList<Exercise> elist,
Button startStopButton, TextView countdownText,
CountdownHandler cHandler) {
this.cHandler = cHandler;
eq = new ArrayDeque<Exercise>(elist);
this.start();
}
public final void cancel() {
mHandler.removeMessages(MSG);
}
private synchronized final ExerciseMeCountDownTimer start() {
if (!eq.isEmpty()) {
Exercise e = eq.pop();
this.mMillisInFuture = Long.parseLong(e.getDuration());
this.mCountdownInterval = 30;
this.name = e.getName();
} else {
onFinish();
return this;
}
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
public void onTick(long millisUntilFinished) {
Message msg = cHandler.obtainMessage(MSG_COUNTDOWN);
Bundle data = new Bundle();
String text = String.format(Locale.GERMANY, "%02d:%02d:%03d",
millisUntilFinished / 100000, millisUntilFinished / 1000,
millisUntilFinished % 1000);
data.putString("countdown", text);
msg.setData(data);
cHandler.sendMessage(msg);
}
public void onFinish() {
if (!eq.isEmpty()) {
this.start();
}
Message msg = cHandler.obtainMessage(MSG_FINISH);
Bundle data = new Bundle();
String text = String.format(Locale.GERMANY, "00:00:000");
data.putString("finish", text);
msg.setData(data);
cHandler.sendMessage(msg);
}
private static final int MSG = 1;
// handles counting down
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
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;
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
};
@Override
public String toString() {
return this.name;
}
}
重要的部分是sendMessage
部分,我将倒计时剩余的时间发送到我handler
的{{1}},然后应该更新文本视图。
MainActivity
最后更新import android.os.Handler;
import android.os.Message;
class CountdownHandler extends Handler {
private static final int MSG_COUNTDOWN = 100;
private static final int MSG_FINISH = 99;
private MainActivity mActivity;
CountdownHandler(MainActivity activity) {
this.mActivity = activity;
}
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_COUNTDOWN) {
String text = msg.getData().getString("countdown");
this.mActivity.sayLog(text);
}
if (msg.what == MSG_FINISH) {
String text = msg.getData().getString("finish");
this.mActivity.sayLog(text);
}
}
textView
MainActivty
调用ExerciseMeCountDownTimer
public void sayLog(String text) {
countdown.setText(text);
}
on onClick()。
问题是,有时(实际上大部分时间)textView没有正确更新。它会在00:05:211等随机时间停止更新 有人会介意告诉我为什么会这样吗?也许还要添加一个解决方案或至少一些文献(可能指出一些部分)我应该阅读以理解这个问题?我也是替代方法,因为我是这个“处理程序”的新手,是android中的“线程”。
修改
new ExerciseMeCountDownTimer(elist, cHandler);
方法中的相应textview。 答案 0 :(得分:1)
使用Handler
和这种情况下的事情使它变得过于复杂。
CountDownTimer
onTick()
和onFinish()
都在UI Thread
上运行,因此可以从任一方法更新TextViews
和其他View
很容易就是通过将View
的引用传递给类的构造函数,就像您已经在做的那样。然后,您只需在所需的方法中更新它。
// could create a member variable for the TextView with your other member variables
...
mTV;
然后在你的构造函数中分配它 //删除了对Handler的引用 - 您已经在这里引用了TextView public ExerciseMeCountDownTimer(ArrayList elist, 按钮startStopButton,TextView countdownText){ mTV = countdownText;
然后以任何需要的方法更新
public void onTick(long millisUntilFinished) {
String text = String.format(Locale.GERMANY, "%02d:%02d:%03d",
millisUntilFinished / 100000, millisUntilFinished / 1000,
millisUntilFinished % 1000);
mTV.setText(text); // set the text here
}
public void onFinish() {
if (!eq.isEmpty()) {
this.start();
}