本文微信公众号「AndroidTraveler」首发。

背景

在 Android 列表开发过程中,有时候我们的 Item 会有一些组件,比如倒计时。这类组件要求不断刷新,这个时候由于列表复用的机制,因此会有一些坑。那么我们本篇文章就给大家讲两个主题。

第一个是列表复用是否一定有问题。
第二个是出现问题有哪些解决方案可供我们选择。

小 Demo

由于我们的主题重点是为了解决不断刷新问题,因此关于 RecyclerView 的基本使用就不再赘述,不清楚的小伙伴可以看下我之前的文章:
RecyclerView基本使用

首先我们看下效果图:

很简单,就是一个 RecyclerView 列表,列表项有两个组件。分别代表第几项和剩余秒数。

这里就是通过倒计时来演示刷新可能存在的问题。

重点代码是 Adapter 里面的显示逻辑,初始为:

@Override public void onBindViewHolder(RecyclerViewViewHolder holder, int position) {     holder.mTvNum.setText(String.valueOf(position + 1));     updateTime(holder, itemList.get(position)); }  private void updateTime(final RecyclerViewViewHolder holder, final long time) {     String content;     long remainTime = time - System.currentTimeMillis();     remainTime /= 1000;     if (remainTime <= 0) {         content = "Time up";         holder.mTxtTitle.setText(content);         return;     }      content = "剩下"+remainTime+"秒";     holder.mTxtTitle.setText(content); }

全部代码见:https://github.com/nesger/RecyclerView/tree/feature/refresh

接下来我们增加刷新方法,有很多种,我们一一说明。

1. 使用 handler 来实现倒计时刷新

修改显示代码,如下:

@Override public void onBindViewHolder(RecyclerViewViewHolder holder, int position) {     holder.mTvNum.setText(String.valueOf(position + 1));     updateTime(holder, itemList.get(position)); }  private void updateTime(final RecyclerViewViewHolder holder, final long time) {     String content;     long remainTime = time - System.currentTimeMillis();     remainTime /= 1000;     if (remainTime <= 0) {         content = "Time up";         holder.mTxtTitle.setText(content);         return;     }      content = "剩下"+remainTime+"秒";     holder.mTxtTitle.setText(content);     holder.mTxtTitle.postDelayed(new Runnable() {         @Override         public void run() {             updateTime(holder, time);         }     }, 1000); }

可以看到通过 handler 延时一秒,然后每次更新时间也是减少一秒。

我们看下效果图:

可以看到没滚动之前还好,滚动之后会发现,倒计时都乱了。

当然有时候可能不会暴露出来,比如滚动数目少,或者只有部分组件有倒计时,不像我们这个例子,所有项目都有倒计时,但是这也间接留下了可能的坑。

出现这个问题的原因在于组件的复用,如果你用 ListView 演示,并且不用复用,那么是不会错乱的。

当然列表不复用这个肯定是不推荐的。

因此,该方式不推荐

全部代码见:https://github.com/nesger/RecyclerView/tree/feature/refresh_1

2. 使用 Timer 来实现倒计时刷新

@Override public void onBindViewHolder(RecyclerViewViewHolder holder, int position) {     holder.mTvNum.setText(String.valueOf(position + 1));     updateTime(holder, itemList.get(position)); }  private void updateTime