正题
RecyclerView 的回收复用机制的内部实现都是由 Recycler 内部类实现,下面就都以这样一种页面的滑动场景来讲解 RecyclerView 的回收复用机制。
这个页面每行可显示5个卡位,每个卡位的 item 布局 type 一致。
开始分析回收复用机制之前,先提几个问题:
Q1:如果向下滑动,新一行的5个卡位的显示会去复用缓存的 ViewHolder,第一行的5个卡位会移出屏幕被回收,那么在这个过程中,是先进行复用再回收?还是先回收再复用?还是边回收边复用?也就是说,新一行的5个卡位复用的 ViewHolder 有可能是第一行被回收的5个卡位吗?
第二个问题之前,先看几张图片:
黑框表示屏幕,RecyclerView 先向下滑动,第三行卡位显示出来,再向上滑动,第三行移出屏幕,第一行显示出来。我们分别在 Adapter 的 onCreateViewHolder() 和 onBindViewHolder() 里打日志,下面是这个过程的日志:
红框1是 RecyclerView 向下滑动操作的日志,第三行5个卡位的显示都是重新创建的 ViewHolder ;红框2是再次向上滑动时的日志,第一行5个卡位的重新显示用的 ViewHolder 都是复用的,因为没有 create viewHolder 的日志,然后只有后面3个卡位重新绑定数据,调用了onBindViewHolder();那么问题来了:
Q2: 在这个过程中,为什么当 RecyclerView 再次向上滑动重新显示第一行的5个卡位时,只有后面3个卡位触发了 onBindViewHolder() 方法,重新绑定数据呢?明明5个卡位都是复用的。
在上面的操作基础上,我们继续往下操作:
在第二个问题操作的基础上,目前已经创建了15个 ViewHolder,此时显示的是第1、2行的卡位,那么继续向下滑动两次,这个过程的日志如下:
红框1是第二个问题操作的日志,在这里截出来只是为了显示接下去的日志是在上面的基础上继续操作的;
红框2就是第一次向下滑时的日志,对比问题2的日志,这次第三行的5个卡位用的 ViewHolder 也都是复用的,而且也只有后面3个卡位触发了 onBindViewHolder() 重新绑定数据;
红框3是第二次向下滑动时的日志,这次第四行的5个卡位,前3个的卡位用的 ViewHolder 是复用的,后面2个卡位的 ViewHolder 则是重新创建的,而且5个卡位都调用了 onBindViewHolder() 重新绑定数据;
那么,
Q3:接下去不管是向上滑动还是向下滑动,滑动几次,都不会再有 onCreateViewHolder() 的日志了,也就是说 RecyclerView 总共创建了17个 ViewHolder,但有时一行的5个卡位只有3个卡位需要重新绑定数据,有时却又5个卡位都需要重新绑定数据,这是为什么呢?
如果明白 RecyclerView 的回收复用机制,那么这三个问题也就都知道原因了;反过来,如果知道这三个问题的原因,那么理解 RecyclerView 的回收复用机制也就更简单了;所以,带着问题,在特定的场景下去分析源码的话,应该会比较容易。