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 中的多个同时倒计时计时器的主要内容,如果未能解决你的问题,请参考以下文章

android 实现同时多个倒计时效果怎么做

如何处理 ListView 中的多个倒数计时器?

android小部件内ListView中的多个可点击项目

ArrayIndexOutOfBoundsException 与 ListView 中的多个视图的自定义 Android 适配器

同一个页面多个倒计时同时进行

使用android中的自定义arrayadapter在listview中使用复选框检查后如何删除多个项目?