我正在开发一个Android应用程序,在一个屏幕上我有Listview
每行都有倒数计时器。我正在使用列表适配器。我试过谷歌和其他参考,但没有得到实际的输出。我从web服务返回秒数,我将秒转换为hh:mm:ss
格式并使用CountdownTimer
类启动倒数计时器。但是当我滚动Listview时它会改变行为,我知道这是android Listview
的常见问题,但我想在每一行显示倒数计时器,并且每秒都有完整的移动时间。
请帮助我的朋友,提前致谢。
答案 0 :(得分:0)
您可以创建一个将在每一行中处理计时器的类。我的意思是一个可重复使用的课程。你已经创建了一个类来使你的计时器然后利用它。在那个类中,你应该能够监视你的listview项目,以便计时器将继续运行。你可以引用该listitem的id。
希望它能给你一些提示
答案 1 :(得分:0)
在CountDownTimer中,不要直接更新listview-item中的textviews,而是从适配器更新数据对象中的一些String。 然后让另一个单独的CountDownTimer调用adapter.notifyDataSetChanged()让listitem-views自行更新。我在代码中称这个为adapterNotifier。
如果每个其他单个CountDownTimer本身都调用adatper.notifyDataSetChanged(),那么adapterNotifier应该单独调用adapter.notifyDataSetChanged()以避免额外的开销。
在来自适配器的getView()方法中,不要做任何花哨的事情,只能从数据对象中读取预先计算的字符串并照常更新文本视图。
这种方法的主要缺点是,您更新了整个每个列表项,如果您有例如列表项目中的网络加载图像。我会尝试进一步优化这一点。
这是一些代码
public Adapter(Context context, ListData dataList) {
super(context, dataList);
this.dataList = dataList;
initTimerData(dataList);
}
private void initTimerData(ListData dataList) {
long longestTimerInterval = 0;
for (final Data data : dataList) {
if (data.show_timer) {
if (data.end_time == null) {
data.show_timer = false;
continue;
}
long endTimeMillis = 0;
try {
endTimeMillis = dataDateTimeProcessor.parse(data.end_time).getTime();
} catch (ParseException e) {
Log.e(DataDetailFragment.class.getSimpleName(), "Error parsing data-time: ", e);
}
// TODO use the server-time for reliability
long nowTime = System.currentTimeMillis();
long timeInterval = endTimeMillis - nowTime;
// if the data is over or more than 24 hours away, don't display the timer
if (nowTime >= endTimeMillis ||
timeInterval > 24 * 3600 * 1000) {
data.show_timer = false;
continue;
}
// save the longest interval for an extra adapter-notifier timer
if (timeInterval > longestTimerInterval)
longestTimerInterval = timeInterval;
// this listener holds the references to the currently visible data-timerviews
DataCountDownTimerListener timerListener = new DataCountDownTimerListener() {
@Override
public void onTick(long millisUntilFinished) {
int seconds = (int) ((millisUntilFinished / 1000) % 60);
int minutes = (int) ((millisUntilFinished / (60000)) % 60);
int hours = (int) ((millisUntilFinished / (3600000)) % 24);
data.timerSeconds = String.format("%02d", seconds);
data.timerMinutes = String.format("%02d", minutes);
data.timerHours = String.format("%02d", hours);
}
@Override
public void onFinish() {
data.timerSeconds = "00";
data.timerMinutes = "00";
data.timerHours = "00";
}
};
if (data.endTimer != null) {
Utils.stopDataTimer(data);
}
data.endTimer = new DataCountDownTimer(timeInterval, 1000);
data.endTimer.setDataCountDownTimerListener(timerListener);
data.endTimer.start();
} else {
data.show_timer = false;
}
}
initAdapterNotifier(longestTimerInterval);
}
private void initAdapterNotifier(long longestTimerInterval) {
// no timers here, go away
if (longestTimerInterval == 0)
return;
adapterNotifier = new DataCountDownTimer(longestTimerInterval, 1000);
DataCountDownTimerListener adapterNotifierListener = new DataCountDownTimerListener() {
@Override
public void onTick(long millisUntilFinished) {
// TODO evaluate performance
// update the adapter-dataset for timer-refreshes
notifyDataSetChanged();
}
@Override
public void onFinish() {
// last timer finished, nothing to do here
}
};
adapterNotifier.setDataCountDownTimerListener(adapterNotifierListener );
adapterNotifier.start();
}
public void stopDataTimers() {
if (adapterNotifier != null)
adapterNotifier.cancel();
for (Data data : dataList) {
if (data.endTimer != null) {
Utils.stopDataTimer(data);
}
}
}