Android:ListView 中的多个同时倒计时计时器
Posted
技术标签:
【中文标题】Android:ListView 中的多个同时倒计时计时器【英文标题】:Android: Multiple simultaneous count-down timers in a ListView 【发布时间】:2011-09-14 19:43:10 【问题描述】:我正在创建一个应用程序,该应用程序需要一个具有不确定数量元素的 ListView,每个元素都有一个从可变数字倒计时的计时器。我能够成功地让其中 一个 倒计时,但我不知道如何在 ListView 的每个元素中包含一个计时器。
我目前使用的是CountDownTimer(如果从网站复制,请确保将 D 大写,他们错了)。
非常感谢任何可以为我指明正确方向的代码或资源。
这是我当前的 EventAdapter 类,它设置每个 ListView 元素的 TextView 中显示的文本。我需要做的是让 TextView 每秒倒计时。由于 ListView 的每个元素都显示不同的内容,我想我需要一种区分每个元素的方法。
我可以每秒更新整个列表,但是我没有包括其他元素,例如从互联网加载的图像,每秒刷新一次是不切实际的。
private class EventAdapter extends ArrayAdapter<Event>
private ArrayList<Event> items;
public EventAdapter(Context context, int textViewResourceId, ArrayList<Event> items)
super(context, textViewResourceId, items);
this.items = items;
@Override
public View getView(int position, View convertView, ViewGroup parent)
View v = convertView;
if (v == null)
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
Event e = items.get(position);
if (e != null)
TextView tv = (TextView) v.findViewById(R.id.text);
if (tv != null)
tv.setText(e.getName());
return v;
【问题讨论】:
您能否给我们提供更多您迄今为止编写的代码示例?在不知道自己写了什么的情况下,很难猜出哪里出了问题。 这不是什么问题,我只是不知道如何开始实施它。但我会在几秒钟内发布一些代码 我实际上有同样的问题,并打算使用从 rxJava 运行 myClickMethod() 方法的单例 CountDownTimer,其中每个视图都订阅了该事件并获得通知以更新其状态。我只是将其视为某种解决方案。 请看看这个答案***.com/a/40236877/5644410 【参考方案1】:这是我做这件事的一个例子,效果很好:
public class TestCounterActivity extends ListActivity
TestAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
// Example values
ArrayList<Date> values = new ArrayList<Date>();
values.add(new Date(1482464366239L));
values.add(new Date(1480464366239L));
values.add(new Date(1470464366239L));
values.add(new Date(1460464366239L));
values.add(new Date(1450464366239L));
values.add(new Date(1440464366239L));
values.add(new Date(1430464366239L));
values.add(new Date(1420464366239L));
values.add(new Date(1410464366239L));
values.add(new Date(1490464366239L));
adapter = new TestAdapter(this, values);
setListAdapter(adapter);
@Override
protected void onStop()
super.onStop();
// Dont forget to cancel the running timers
adapter.cancelAllTimers();
这是适配器
public class TestAdapter extends ArrayAdapter<Date>
private final Activity context;
private final List<Date> values;
private HashMap<TextView,CountDownTimer> counters;
static class TestViewHolder
public TextView tvCounter;
public TestAdapter(Activity context, List<Date> values)
super(context, R.layout.test_row, values);
this.context = context;
this.values = values;
this.counters = new HashMap<TextView, CountDownTimer>();
@Override
public View getView(int position, View convertView, ViewGroup parent)
View rowView = convertView;
if(rowView == null)
LayoutInflater inflater = context.getLayoutInflater();
rowView = inflater.inflate(R.layout.test_row, null);
final TestViewHolder viewHolder = new TestViewHolder();
viewHolder.tvCounter = (TextView) rowView.findViewById(R.id.tvCounter);
rowView.setTag(viewHolder);
TestViewHolder holder = (TestViewHolder) rowView.getTag();
final TextView tv = holder.tvCounter;
CountDownTimer cdt = counters.get(holder.tvCounter);
if(cdt!=null)
cdt.cancel();
cdt=null;
Date date = values.get(position);
long currentDate = Calendar.getInstance().getTime().getTime();
long limitDate = date.getTime();
long difference = limitDate - currentDate;
cdt = new CountDownTimer(difference, 1000)
@Override
public void onTick(long millisUntilFinished)
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
String sDate = "";
if(millisUntilFinished > DateUtils.DAY_IN_MILLIS)
days = (int) (millisUntilFinished / DateUtils.DAY_IN_MILLIS);
sDate += days+"d";
millisUntilFinished -= (days*DateUtils.DAY_IN_MILLIS);
if(millisUntilFinished > DateUtils.HOUR_IN_MILLIS)
hours = (int) (millisUntilFinished / DateUtils.HOUR_IN_MILLIS);
millisUntilFinished -= (hours*DateUtils.HOUR_IN_MILLIS);
if(millisUntilFinished > DateUtils.MINUTE_IN_MILLIS)
minutes = (int) (millisUntilFinished / DateUtils.MINUTE_IN_MILLIS);
millisUntilFinished -= (minutes*DateUtils.MINUTE_IN_MILLIS);
if(millisUntilFinished > DateUtils.SECOND_IN_MILLIS)
seconds = (int) (millisUntilFinished / DateUtils.SECOND_IN_MILLIS);
sDate += " "+String.format("%02d",hours)+":"+String.format("%02d",minutes)+":"+String.format("%02d",seconds);
tv.setText(sDate.trim());
@Override
public void onFinish()
tv.setText("Finished");
;
counters.put(tv, cdt);
cdt.start();
return rowView;
public void cancelAllTimers()
Set<Entry<TextView, CountDownTimer>> s = counters.entrySet();
Iterator it = s.iterator();
while(it.hasNext())
try
Map.Entry pairs = (Map.Entry)it.next();
CountDownTimer cdt = (CountDownTimer)pairs.getValue();
cdt.cancel();
cdt = null;
catch(Exception e)
it=null;
s=null;
counters.clear();
【讨论】:
感谢您的出色解决方案! 是的,对我也有帮助,谢谢 谢谢,它简单而出色的解决方案,节省了我的时间。【参考方案2】:请查看here at my blog,您将在其中找到有关如何实现此目的的示例。
一种解决方案是将表示每个计数器的 TextView 与其在列表中的位置一起作为键放入一个 HashMap 中。
在getView()中
TextView counter = (TextView) v.findViewById(R.id.myTextViewTwo);
if (counter != null)
counter.setText(myData.getCountAsString());
// add the TextView for the counter to the HashMap.
mCounterList.put(position, counter);
然后您可以使用 Handler 和发布可运行文件的位置来更新计数器。
private final Runnable mRunnable = new Runnable()
public void run()
MyData myData;
TextView textView;
// if counters are active
if (mCountersActive)
if (mCounterList != null && mDataList != null)
for (int i=0; i < mDataList.size(); i++)
myData = mDataList.get(i);
textView = mCounterList.get(i);
if (textView != null)
if (myData.getCount() >= 0)
textView.setText(myData.getCountAsString());
myData.reduceCount();
// update every second
mHandler.postDelayed(this, 1000);
;
【讨论】:
Please provide context for links。至少在您的答案中直接包含要点,最好包括代码示例。可以参考您的博客了解更多详细信息,但即使读者选择不点击链接,您的回答也应该有意义。【参考方案3】:在检查了几种方法后,这是我写的一个创造性的解决方案。它简单且完美。
检查更新数据的Runnable
是否更新相同的TextView
以及如果TextView
与不同的视图相关Runnable
将停止的想法,通过这种方式不会有额外的Thread
's 在后台,所以不会有闪烁的文本或内存泄漏。
1 .在您的 getView()
中添加每个 TextView 标记和他的位置。
text = (TextView) view
.findViewById(R.id.dimrix);
text.setTag(position);
2 。创建实现 Runnable 的类,以便我们可以传递参数。
public class mUpdateClockTask implements Runnable
private TextView tv;
final Handler mClockHandler = new Handler();
String tag;
public mUpdateClockTask(TextView tv,
String tag)
this.tv = tv;
this.tag = tag;
public void run()
if (tv.getTag().toString().equals(tag))
// do what ever you want to happen every second
mClockHandler.postDelayed(this, 1000);
;
所以这里发生的情况是除非TextView
不等于Runnable
将停止的原始标签。
3 .回到你的getView()
final Handler mClockHandler = new Handler();
mUpdateClockTask clockTask = new mUpdateClockTask(text,
activeDraw, text.getTag().toString());
mClockHandler.post(clockTask);
就是这样,工作完美!
【讨论】:
谢谢,这是一个非常古老的问题,我不再从事这个项目,但也许您的回答会对其他人有所帮助。 这就是想法,我相信你现在已经弄清楚了(-: 这就是答案【参考方案4】:这里是使用 ListView 和多个 CountDownTimer 的另一种解决方案。首先,我们创建一个包含 CountDownTimer 的类 MyCustomTimer:
public class MyCustomTimer
public MyCustomTimer()
public void setTimer(TextView tv, long time)
new CountDownTimer(time, 1000)
public void onTick(long millisUntilFinished)
//Set formatted date to your TextView
tv.setText(millisUntilFinished);
public void onFinish()
tv.setText("Done!");
.start();
然后,在你的适配器中初始化创建的类:
public class MyAdapter extends BaseAdapter
private LayoutInflater mInflater;
private MyCustomTimer myTimer;
private ArrayList<Item> myItems;
public MyAdapter(Context context, ArrayList<Item> data)
mInflater = LayoutInflater.from(context);
myTimer= new MyCustomTimer();
myItems = data;
//... implementation of other methods
@Override
public View getView(int position, View convertView, ViewGroup parent)
convertView = mInflater.inflate(R.layout.listview_row, null);
TextView tvTimer = (TextView) convertView.findViewById(R.id.textview_timer);
TextView tvName = (TextView) convertView.findViewById(R.id.textview_name);
Item item = data.get(position);
tvName.setText(item.getName());
myTimer.setTimer(tvTimer, item.getTime());
return convertView;
【讨论】:
当然不行。它为每个视图创建新的 CountDownTimer ,而不检查其新视图还是现有视图。滚动一次后,每个视图上都会有多个 CountDownTimer 。以上是关于Android:ListView 中的多个同时倒计时计时器的主要内容,如果未能解决你的问题,请参考以下文章
ArrayIndexOutOfBoundsException 与 ListView 中的多个视图的自定义 Android 适配器