Android如何利用RecyclerView实现列表倒计时效果实例代码

作者:冬季穿短裤 时间:2023-01-24 08:08:53 

前言

最近面试时,面试官问了一个列表倒计时效果如何实现,然后脑袋突然懵的了O(∩_∩)O,现在记录一下。

运行效果图

Android如何利用RecyclerView实现列表倒计时效果实例代码

实现思路

实现方法主要有两个:

1.为每个开始倒计时的item启动一个定时器,再做更新item处理;

2.只启动一个定时器,然后遍历数据,再做再做更新item处理。

经过思考,包括性能、实现等方面,决定使用第2种方式实现。

实现过程

数据实体


/**
* 总共的倒计时的时间(结束时间-开始时间),单位:毫秒
* 例: 2019-02-23 11:00:30 与 2019-02-23 11:00:00 之间的相差的毫秒数
*/
private long totalTime;
/**
* 倒计时是否在暂停状态
*/
private boolean isPause = true;

倒计时

Timer


mTimer.schedule(mTask, 0, 1000);

TimerTask


class MyTask extends TimerTask {
 @Override
 public void run() {
  if (mList.isEmpty()) {
   return;
  }
  int size = mList.size();
  CountDownTimerBean bean;
  long totalTime;
  for (int i = 0; i < size; i++) {
   bean = mList.get(i);
   if (!bean.isPause()) {//不处于暂停状态
    totalTime = bean.getTotalTime() - 1000;
    if (totalTime <= 0) {
     bean.setPause(true);
     bean.setTotalTime(0);
    }
    bean.setTotalTime(totalTime);
    Message message = mHandler.obtainMessage(1);
    message.arg1 = i;
    mHandler.sendMessage(message);
   }
  }
 }
}

线程交互更新item


mHandler = new Handler(Looper.getMainLooper()) {
  @Override
  public void handleMessage(Message msg) {
   switch (msg.what) {
    case 1:
     notifyItemChanged(msg.arg1, "update-time");
     break;
   }
  }
 };

性能优化方面

1.调用notifyItemChanged()方法后,不要更新整个item(比如说item包含图片,不需要变的),所以要重写onBindViewHolder( Holder , int , List


@Override
public void onBindViewHolder(@NonNull Holder holder, int position, @NonNull List<Object> payloads) {
 if (payloads.isEmpty()) {
  onBindViewHolder(holder, position);
  return;
 }
 //更新某个控件,比如说只需要更新时间信息,其他不用动
 CountDownTimerBean bean = mList.get(position);
 long day = bean.getTotalTime() / (1000 * 60 * 60 * 24);
 long hour = (bean.getTotalTime() / (1000 * 60 * 60) - day * 24);
 long min = ((bean.getTotalTime() / (60 * 1000)) - day * 24 * 60 - hour * 60);
 long s = (bean.getTotalTime() / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
 holder.tvTime.setText("剩余时间: " + day + "天" + hour + "小时" + min + "分" + s + "秒");
 holder.btnAction.setText(bean.isPause() ? "开始" : "暂停");
 holder.btnAction.setEnabled(bean.getTotalTime() != 0);
}

2.销毁资源操作:


/**
 * 销毁资源
 */
public void destroy() {
 mHandler.removeMessages(1);
 if (mTimer != null) {
  mTimer.cancel();
  mTimer.purge();
  mTimer = null;
 }
}

RecyclerView.Adapter部分源码


public class CountDownTimerAdapter extends RecyclerView.Adapter<CountDownTimerAdapter.Holder> {
private static final String TAG = "CountDownTimerAdapter->";
private List<CountDownTimerBean> mList;//数据
private Handler mHandler;//线程调度,用来更新列表

private Timer mTimer;
private MyTask mTask;

public CountDownTimerAdapter() {
 mList = new ArrayList<>();
 mHandler = new Handler(Looper.getMainLooper()) {
  @Override
  public void handleMessage(Message msg) {
   switch (msg.what) {
    case 1:
     notifyItemChanged(msg.arg1, "update-time");
     break;
   }
  }
 };
 mTask = new MyTask();
}

public void bindAdapterToRecyclerView(@NonNull RecyclerView view) {
 view.setAdapter(this);
}

/**
 * 设置新的数据源
 *
 * @param list 数据
 */
public void setNewData(@NonNull List<CountDownTimerBean> list) {
 destroy();
 mList.clear();
 mList.addAll(list);
 notifyDataSetChanged();
 if (mTimer == null) {
  mTimer = new Timer();
 }
 mTimer.schedule(mTask, 0, 1000);
}

/**
 * 销毁资源
 */
public void destroy() {
 mHandler.removeMessages(1);
 if (mTimer != null) {
  mTimer.cancel();
  mTimer.purge();
  mTimer = null;
 }
}

@NonNull
@Override
public Holder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
 View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_count_down_timer, viewGroup, false);
 return new Holder(view);
}

@Override
public void onBindViewHolder(@NonNull Holder holder, int position, @NonNull List<Object> payloads) {
 if (payloads.isEmpty()) {
  onBindViewHolder(holder, position);
  return;
 }
 //更新某个控件,比如说只需要更新时间信息,其他不用动
 CountDownTimerBean bean = mList.get(position);
 long day = bean.getTotalTime() / (1000 * 60 * 60 * 24);
 long hour = (bean.getTotalTime() / (1000 * 60 * 60) - day * 24);
 long min = ((bean.getTotalTime() / (60 * 1000)) - day * 24 * 60 - hour * 60);
 long s = (bean.getTotalTime() / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
 holder.tvTime.setText("剩余时间: " + day + "天" + hour + "小时" + min + "分" + s + "秒");
 holder.btnAction.setText(bean.isPause() ? "开始" : "暂停");
 holder.btnAction.setEnabled(bean.getTotalTime() != 0);
}

@Override
public void onBindViewHolder(@NonNull final Holder holder, int position) {
 holder.ivIcon.setImageResource(R.mipmap.ic_launcher_round);
 final CountDownTimerBean bean = mList.get(position);
 long day = bean.getTotalTime() / (1000 * 60 * 60 * 24);
 long hour = (bean.getTotalTime() / (1000 * 60 * 60) - day * 24);
 long min = ((bean.getTotalTime() / (60 * 1000)) - day * 24 * 60 - hour * 60);
 long s = (bean.getTotalTime() / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
 holder.tvTime.setText("剩余时间: " + day + "天" + hour + "小时" + min + "分" + s + "秒");
 holder.btnAction.setText(bean.isPause() ? "开始" : "暂停");
 holder.btnAction.setEnabled(bean.getTotalTime() != 0);
 holder.btnAction.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   if (bean.isPause()) {
    bean.setPause(false);
    holder.btnAction.setText("暂停");
   } else {
    bean.setPause(true);
    holder.btnAction.setText("开始");
   }
  }
 });
}

@Override
public int getItemCount() {
 return mList.size();
}

class Holder extends RecyclerView.ViewHolder {
 private ImageView ivIcon;
 private TextView tvTime;
 private Button btnAction;

Holder(@NonNull View itemView) {
  super(itemView);
  ivIcon = itemView.findViewById(R.id.iv_icon);
  tvTime = itemView.findViewById(R.id.tv_time);
  btnAction = itemView.findViewById(R.id.btn_action);
 }
}

class MyTask extends TimerTask {
 @Override
 public void run() {
  if (mList.isEmpty()) {
   return;
  }
  int size = mList.size();
  CountDownTimerBean bean;
  long totalTime;
  for (int i = 0; i < size; i++) {
   bean = mList.get(i);
   if (!bean.isPause()) {//不处于暂停状态
    totalTime = bean.getTotalTime() - 1000;
    if (totalTime <= 0) {
     bean.setPause(true);
     bean.setTotalTime(0);
    }
    bean.setTotalTime(totalTime);
    Message message = mHandler.obtainMessage(1);
    message.arg1 = i;
    mHandler.sendMessage(message);
   }
  }
 }
}
}

项目地址

源码

来源:https://www.cnblogs.com/qq714081644/p/6547192.html

标签:android,recyclerview,倒计时
0
投稿

猜你喜欢

  • Android 文件存储与SharedPreferences存储方式详解用法

    2021-07-22 20:11:54
  • Android Studio自动提取控件Style样式教程

    2022-01-29 14:09:55
  • Java中的匿名内部类小结

    2021-05-29 06:29:38
  • Java操作FreeMarker模板引擎的基本用法示例小结

    2022-01-15 11:34:15
  • C# 对XML基本操作代码总结

    2022-08-21 16:09:09
  • C#实现利用泛型将DataSet转为Model的方法

    2023-09-12 13:32:26
  • java注解的全面分析

    2023-11-25 11:28:50
  • spring声明式事务 @Transactional 不回滚的多种情况以及解决方案

    2023-07-06 10:50:33
  • 解决Springboot2.1.x配置Activiti7单独数据源问题

    2022-07-28 02:24:04
  • SpringBoot登录拦截配置详解(实测可用)

    2023-04-22 20:52:21
  • Maven中怎么手动添加jar包到本地仓库详解(repository)

    2023-09-08 07:33:20
  • 分享几个Java工作中实用的代码优化技巧

    2023-11-28 12:04:50
  • C#中泛型举例List<T>与DataTable相互转换

    2021-07-06 18:54:08
  • Java类加载器和类加载机制实例分析

    2021-07-18 03:32:26
  • Spring整合Quartz实现定时任务调度的方法

    2023-07-07 00:55:55
  • 一文带你了解C#中的协变与逆变

    2022-08-06 22:31:21
  • java理论基础Stream元素的匹配与查找

    2021-08-26 10:11:20
  • c#实现摄像头拍照功能示例

    2023-07-11 09:54:06
  • Spring Cloud Feign接口返回流的实现

    2021-06-07 07:21:54
  • MybatisX-Generator自动代码生成插件教程

    2022-01-08 10:50:48
  • asp之家 软件编程 m.aspxhome.com