【问题标题】:Updating TextView in RecyclerView Adapter on Timer without NotifyDatasetChange()在没有 NotifyDatasetChanged() 的 Timer 上更新 RecyclerView Adapter 中的 TextView
【发布时间】:2021-04-06 01:41:23
【问题描述】:

我的用例非常简单,我有一个RecyclerView,RecyclerView 中的每个项目都有一个计时器,它应该运行倒计时到 10 秒(例如)并更新 TextView 中的 @987654327 @ 每秒以秒为单位显示剩余时间。

我创建了一个定时器类如下

public class BurnTimerTask2
    {
        private System.Timers.Timer t = new System.Timers.Timer(1000);
        private int Secs;
        private TextView tv;
        public BurnTimerTask2(int Secs, TextView tv)
        {
            this.Secs = Secs;
            this.tv = tv;
            t.Elapsed += T_Elapsed;
            t.Start();
        }

        private void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Android.Util.Log.Debug("PMBurnTimers", "Timer: " + Secs);
            Secs--;
            tv.Text = Secs + " Seconds left";
            if (Secs == 0)
                t.Stop();
        }
    }

在我的OnBindViewHolder,我这样称呼它

if (!MYLIST[position].TimerTriggered)
{                                       
  MYLIST[position].TimerTriggered= true;
  new BurnTimerTask2(10, viewHolder.Textview);
}
else
{                   
  viewHolder.Textview.Text = "TIMER ALREADY TRIGGERED";                                      
}

new BurnTimerTask2(10, viewHolder.Textview); 是我调用计时器类并传递TextView 的地方(在上面的代码中,我正在检查是否已触发计时器,如果已触发,则不调用计时器类,所以我没有针对同一项目的多个计时器)

问题:

1- TextView 显示秒数不会更新,除非我稍微滚动RecyclerView,一旦我稍微滚动RecyclerView,它就会开始滴答作响并按预期更新TextView 的文本。

2- 一旦调用 Timer 类,我的Activity 中的 UI 就会无响应,我无法在几秒钟内与RecyclerView 之外的任何东西进行交互,如果我可以点击,它会变得如此缓慢一个按钮,它需要永远触发该按钮上的操作。 (注意:这仅在我更新TextView 时发生,如果我不更新TextView 并自行运行计时器,一切正常,所以确定不是导致它的计时器,而是从导致它的计时器更新TextView)

显然我没有以正确的方式更新 TextView。我尝试了以下

1- 在适配器中运行计时器(同样的问题)

2- 为此处指出的ViewHolder 中的每个项目创建一个计时器Countdown timer in recyclerview not working properly(同样的问题)

根据以下文章,我正在做的应该只是简单的工作,但它没有 How to handle multiple countdown timers in RecyclerView? 和 https://github.com/Manikkumar1988/TimerInRecyclerView

我不知道如何解决这个问题。任何想法

【问题讨论】:

  • 您可以在适配器中使用单个计时器使用 notifyItemChange 和有效负载。
  • @ADM 如果我的所有项目都运行不同的倒计时(10 秒、20 秒、30 秒等)计时器,如何在适配器中使用单个计时器?
  • 一个计时器将提供每秒钟一次的调用。因此,如果您有每个项目的开始时间,您只需计算当前差异并将其设置为文本视图。
  • @ADM 理解,但是当我有 3 个项目可见(例如)并且如果我正在计算 onBindViewHolder 中的时间差,我该如何同时为 3 个项目执行此操作,而我只有一个计时器滴答作响的实例?
  • 我说你创建了一个全局倒计时计时器,它将为你提供第二个 Tick。在 bindViewHolder 的两个变体中,您可以计算 System.currentTimeInMillies-startTime 之间的差异。类似的东西。现在您将从计时器#Tick 方法中调用notifyItemChange(position,payload)。

标签: c# android timer


【解决方案1】:

您好,我有一个使用 Chronometer (https://developer.android.com/reference/android/widget/Chronometer) 的想法。它是 TextView 的子对象,但会自行处理计数和更新 View。

想法是让列表的 viewHolder 保存这个 Chronometer,然后在你的 onBindViewHolder() 中让这个 Chronometer 计算正确的时间(如果每个项目计算不同的时间)。

试试这个适配器,我为列表中的每个项目都有一个单独的计时器,并且 onBindViewHolder 我会将那个计时器绑定到 Chronometer。尝试看看是否可以使用计时器类替换 myTimers[]。


public class SOAdapter extends RecyclerView.Adapter<SOAdapter.ViewHolder> {

    Context context;
    int timerNumber;
    Chronometer[] myTimers;
    SOAdapter(Context context, int timerNumber){
        this.context = context;
        this.timerNumber = timerNumber;
        this.myTimers = new Chronometer[timerNumber];
        for (int i = 0; i < timerNumber; i++){
            Chronometer c = new Chronometer(context);
            c.setTextSize(30);
            c.setBase(SystemClock.elapsedRealtime());
            c.start();
            myTimers[i] = c;
        }
    }

    @NonNull
    @Override
    public SOAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        Chronometer timer = new Chronometer(context);
        timer.setLayoutParams(new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        timer.setTextSize(30);
        timer.setBase(SystemClock.elapsedRealtime());
        timer.start();
        return new ViewHolder(timer);
    }

    @Override
    public void onBindViewHolder(@NonNull SOAdapter.ViewHolder holder, int position) {
        Chronometer cur = myTimers[position];
        holder.bindTimer(cur);
    }

    @Override
    public int getItemCount() {
        return timerNumber;
    }


    public class ViewHolder extends RecyclerView.ViewHolder{
        Chronometer displayTimer;
        ViewHolder(Chronometer timer) {
            super(timer);
            displayTimer = timer;
        }

        public void bindTimer(Chronometer timer){
            displayTimer.setBase(timer.getBase());
        }
    }
}


【讨论】:

  • 这听起来不错,让我试试 :)
  • 好主意,但是ChronoMeter 似乎只向上计数而不是向下计数,我需要倒计时
  • 如果您使用 API > 24,ChronoMeter 支持倒计时“通过将 setCountDown(boolean) 设置为 true,计时器也可以向基准时间倒计时。”这应该可以解决显示问题,但我猜测困难的部分是需要在 onBindViewHolder() 期间正确更新基础
  • 是的,谢谢 :) 我会接受这个答案,因为这是最好的解决方案,但是我最终将 CountDownTimer 作为全局计时器作为上述帖子中的 ADM 建议的那样也可以正常工作。
猜你喜欢
  • 1970-01-01
  • 2021-12-22
  • 2015-09-02
  • 2019-05-05
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多