android 列表倒计时,Android利用RecyclerView实现列表倒计时效果

最近面试时,面试官问了一个列表倒计时效果如何实现,现在记录一下。

运行效果图

2dec973baa35906f2a3ca685ba295f50.gif

实现思路

实现方法主要有两个:

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 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 {

private static final String TAG = "CountDownTimerAdapter->";

private List 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 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 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);

}

}

}

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在RecyclerView实现倒计时,可以通过在RecyclerView的Adapter中使用Handler和Runnable来实现。以下是一个简单的示例: 1. 在ViewHolder中添加一个TextView用于显示倒计时的时间,例如: ```java public class MyViewHolder extends RecyclerView.ViewHolder { TextView countdownTextView; Handler handler; Runnable runnable; public MyViewHolder(View itemView) { super(itemView); countdownTextView = itemView.findViewById(R.id.countdown_textview); handler = new Handler(); runnable = new Runnable() { @Override public void run() { // 更新倒计时的时间 countdownTextView.setText(getTimeLeft()); handler.postDelayed(this, 1000); // 每隔1秒更新一次 } }; } // 计算距离结束时间还剩下的时间 private String getTimeLeft() { long timeLeft = endTime - System.currentTimeMillis(); if (timeLeft <= 0) { return "倒计时已结束"; } else { long seconds = timeLeft / 1000; long minutes = seconds / 60; long hours = minutes / 60; long days = hours / 24; return String.format(Locale.getDefault(), "%02d:%02d:%02d:%02d", days, hours % 24, minutes % 60, seconds % 60); } } // 开始倒计时 public void startCountdown(long endTime) { this.endTime = endTime; handler.post(runnable); } // 停止倒计时 public void stopCountdown() { handler.removeCallbacks(runnable); } } ``` 2. 在Adapter中重写onBindViewHolder方法,在其中调用ViewHolder的startCountdown方法开始倒计时,例如: ```java @Override public void onBindViewHolder(MyViewHolder holder, int position) { // 获取当前item的结束时间 long endTime = data.get(position).getEndTime(); holder.startCountdown(endTime); } ``` 3. 在Activity或Fragment中,在RecyclerView被销毁的时候,调用ViewHolder的stopCountdown方法停止倒计时,例如: ```java @Override protected void onDestroy() { super.onDestroy(); for (int i = 0; i < recyclerView.getChildCount(); i++) { MyViewHolder holder = (MyViewHolder) recyclerView.getChildViewHolder(recyclerView.getChildAt(i)); holder.stopCountdown(); } } ``` 这样就能在RecyclerView实现倒计时了。当然,还可以根据不同的需求进行更加灵活的实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值