Recyclerview implements list countdown

Recently, I was working on a project that needed to use the list countdown function. I finally worked it out after a long time. To achieve this effect in Android, I need to use countdowntimer. Through the use of this class, we can not only achieve the countdown effect, but also perfectly solve two bugs in the process of realizing the countdown.

1. Memory problem 2. The time of different items is disordered due to the reuse of items in recyclerview

First, let's look at the final effect

I'm sure everyone will know how to display the list. Here I only attach the adapter class implemented with the countdown function.

public class ClockAdapter extends RecyclerView.Adapter<ClockAdapter.ClockViewHolder> {
 private SparseArray<CountDownTimer> countDownMap = new SparseArray<>();

 @Override
 public ClockViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
  View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv,parent,false);

  return new ClockViewHolder(view);
 }
 /**
  * 清空资源
  */
 public void cancelAllTimers() {
  if (countDownMap == null) {
   return;
  }
  for (int i = 0,length = countDownMap.size(); i < length; i++) {
   CountDownTimer cdt = countDownMap.get(countDownMap.keyAt(i));
   if (cdt != null) {
    cdt.cancel();
   }
  }
 }

 @Override
 public void onBindViewHolder(final ClockViewHolder holder,int position) {
  long betweenDate;
  if (position == 0) {
   betweenDate= DateUtil.getLeftTime("2017-8-8 12:10:10");
  } else {
   betweenDate= DateUtil.getLeftTime("2017-8-9 15:10:10");
  }

  if (holder.countDownTimer != null) {
   holder.countDownTimer.cancel();
  }

  if (betweenDate > 0) {
   holder.countDownTimer = new CountDownTimer(betweenDate,1000) {
    public void onTick(long millisUntilFinished) {
     millisUntilFinished = millisUntilFinished / 1000;
     int hours = (int) (millisUntilFinished / (60 * 60));
     int leftSeconds = (int) (millisUntilFinished % (60 * 60));
     int minutes = leftSeconds / 60;
     int seconds = leftSeconds % 60;

     final StringBuffer sBuffer = new StringBuffer();
     sBuffer.append(addZeroPrefix(hours));
     sBuffer.append(":");
     sBuffer.append(addZeroPrefix(minutes));
     sBuffer.append(":");
     sBuffer.append(addZeroPrefix(seconds));
     holder.clock.setText(sBuffer.toString());
    }
    public void onFinish() {
//     时间结束后进行相应逻辑处理
    }
   }.start();
   countDownMap.put(holder.clock.hashCode(),holder.countDownTimer);
  } else {
//   时间结束 进行相应逻辑处理
  }

 }

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

 class ClockViewHolder extends RecyclerView.ViewHolder {

  TextView clock;
  CountDownTimer countDownTimer;

  public ClockViewHolder(View itemView) {
   super(itemView);
   clock = (TextView) itemView.findViewById(R.id.clock);
  }
 }
}

The cancelalltimer () method solves the memory problem. Through this line of code, set the hashcode of item as the key into SparseArray, so that it can be taken out one by one in the cancelalltimer method for countdown cancellation.

countDownMap.put(holder.clock.hashCode(),holder.countDownTimer);

Then create a new countdowntimer class through the following line of code

holder.countDownTimer = new CountDownTimer(betweenDate,1000) {
 public void onTick(long millisUntilFinished) {
 millisUntilFinished = millisUntilFinished / 1000;
 int hours = (int) (millisUntilFinished / (60 * 60));
 int leftSeconds = (int) (millisUntilFinished % (60 * 60));
 int minutes = leftSeconds / 60;
 int seconds = leftSeconds % 60;
 final StringBuffer sBuffer = new StringBuffer();
 sBuffer.append(addZeroPrefix(hours));
 sBuffer.append(":")   sBuffer.append(addZeroPrefix(minutes));
     sBuffer.append(":");
     sBuffer.append(addZeroPrefix(seconds));
     holder.clock.setText(sBuffer.toString());
}
public void onFinish() {
// 时间结束后进行相应逻辑处理
}
}.start();

Analyze its source code

public CountDownTimer(long millisInFuture,long countDownInterval) {
  mMillisInFuture = millisInFuture;
  mCountdownInterval = countDownInterval;
 }

It can be clearly seen that two values are set, the first is the end time of countdown, and the second is the interval of refresh time. Then start through the start method, and then look at the processing in the start method

public synchronized final CountDownTimer start() {
  mCancelled = false;
  if (mMillisInFuture <= 0) {
   onFinish();
   return this;
  }
  mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
  mHandler.sendMessage(mHandler.obtainMessage(MSG));
  return this;
 }

In the source code, when the countdown deadline is less than 0, that is, when the countdown is over, the onfinish method is called. If the time is not over, the message is sent through the handler's asynchronous message mechanism. Through the whole process, the final method will go to the handler's handlemessage method. If there are partners who are not familiar with the asynchronous process, You can read an article about asynchronous message mechanism I wrote before. Android asynchronous message mechanism is thoroughly analyzed at the source level. OK, let's take a look at the handler's handlemessage method.

private Handler mHandler = new Handler() {

 @Override
 public void handleMessage(Message msg) {

  synchronized (CountDownTimer.this) {
  if (mCancelled) {
   return;
  }

  final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();

  if (millisLeft <= 0) {
   onFinish();
  } else if (millisLeft < mCountdownInterval) {
  // no tick,just delay until done
  sendMessageDelayed(obtainMessage(MSG),millisLeft);
  } else {
long lastTickStart=SystemClock.elapsedRealtime();
   onTick(millisLeft);
 // take into account user's onTick taking time to execute
 long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();

// special case: user's onTick took more than interval to
// complete,skip to next interval
 while (delay < 0) delay += mCountdownInterval;
  sendMessageDelayed(obtainMessage(MSG),delay);
    }
   }
  }
 };

I believe this source code is still familiar and easy to understand. First, calculate the remaining time. If the remaining time is less than the refresh time, send a delay message until the time ends. If the remaining time is greater than the refresh time, call the ontick (millisleft) method. This method was rewritten when we created the countdowntimer class, In it, we can write the specific logic of our countdown display. This concludes the whole process.

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>