Multiple count down timers in RecyclerView flickering when scrolled

前端 未结 3 1422
孤街浪徒
孤街浪徒 2020-11-30 09:27

I have implemented count down timer for each item of RecyclerView which is in a fragment activity. The count down timer shows the time remaining for expiry. The count down t

3条回答
  •  误落风尘
    2020-11-30 09:46

    There are two types of solution I can think of and they are without using CountDownTimer class

    1. Make Handle with postDelayed method and call notifyDataSetChanged() in that. In your adapter make calculation for timing. like below code.

    in Constructor of adapter class

    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            notifyDataSetChanged();
            handler.postDelayed(this, 1000);
        }
    }, 1000);
    

    and in you onBindViewHolder method

    public void onBindViewHolder(final FeedViewHolder holder, final int position) {
    
          updateTimeRemaining(endTime, holder.yourTextView);
    }
    
    private void updateTimeRemaining(long endTime, TextView yourTextView) {
    
        long timeDiff = endTime - System.currentTimeMillis();
        if (timeDiff > 0) {
            int seconds = (int) (timeDiff / 1000) % 60;
            int minutes = (int) ((timeDiff / (1000 * 60)) % 60);
            int hours = (int) ((timeDiff / (1000 * 60 * 60)) % 24);
    
            yourTextView.setText(MessageFormat.format("{0}:{1}:{2}", hours, minutes, seconds));
        } else {
            yourTextView.setText("Expired!!");
        }
    }
    
    1. if you think notifyDataSetChanged() every millisecond is wrong then here is second option. Create class with Runnable implementation and use in in adapter with setTag() and getTag() method

          public class DownTimer implements Runnable {
      
          private TextView yourTextView;
          private long endTime;
          private DateFormat formatter = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
          private Handler handler = new Handler();
      
          public DownTimer(long endTime, TextView textView) {
              this.endTime = endTime;
              yourTextView = textView;
              formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
          }
      
          public void setEndTime(long endTime) {
              this.endTime = endTime;
          }
      
          public void start() {
              if (handler != null)
                  handler.postDelayed(this, 0);
          }
      
          public void cancel() {
              if (handler != null)
                  handler.removeCallbacks(this);
          }
      
          @Override
          public void run() {
              if (handler == null)
                  return;
      
              if (yourTextView == null && endTime == 0)
                  return;
      
              long timeDiff = endTime - System.currentTimeMillis();
      
              try {
                  Date date = new Date(timeDiff);
                  yourTextView.setText(formatter.format(date));
      
              }catch (Exception e){e.printStackTrace();}
              }
      }
      

    and use in onBindViewHolder like this

    if (holder.yourTextView.getTag() != null) {
        DownTimer downTimer = (DownTimer) holder.yourTextView.getTag();
        downTimer.cancel();
        downTimer.setEndTime(endTime);
        downTimer.start();
    } else {
        DownTimer downTimer = new DownTimer(endTime, holder.yourTextView);
        downTimer.start();
        holder.yourTextView.setTag(downTimer);
    }
    

提交回复
热议问题