文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android架构师之深入理解RecyclerView复用和缓存机制详解

2024-12-02 23:47

关注

前言

学习源码,研究源码编程思想,是程序开发者进阶的必经之路

大家都知道RecyclerView有回收复用机制,那么回收复用机制是如何作用的?

今天我们就用源码来讲解,一起学习

一、Recycler介绍

RecyclerView是通过内部类Recycler管理的缓存,那么Recycler中缓存的是什么?我们知道RecyclerView在存在大量数据时依然可以滑动的如丝滑般顺畅,而RecyclerView本身是一个ViewGroup,那么滑动时避免不了添加或移除子View(子View通过RecyclerView#Adapter中的onCreateViewHolder创建),如果每次使用子View都要去重新创建,肯定会影响滑动的流 畅性,所以RecyclerView通过Recycler来缓存的是ViewHolder(内部包含子View),这样在滑动时可以复用子View,某些条件下还可以复用子View绑定的数据。所以本质上缓存是为了减少重复绘制View和绑定数据的时间,从而提高了滑动时的性能

  1. public final class Recycler { 
  2.         final ArrayList mAttachedScrap = new ArrayList<>(); 
  3.         ArrayList mChangedScrap = null
  4.         final ArrayList mCachedViews = new ArrayList(); 
  5.         private final List 
  6.                 mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap); 
  7.         private int mRequestedCacheMax = DEFAULT_CACHE_SIZE; 
  8.         int mViewCacheMax = DEFAULT_CACHE_SIZE; 
  9.         RecycledViewPool mRecyclerPool; 
  10.         private ViewCacheExtension mViewCacheExtension; 
  11.         static final int DEFAULT_CACHE_SIZE = 2; 

Recycler缓存ViewHolder对象有4个等级,优先级从高到底依次为:

ArrayList mAttachedScrap --- 缓存屏幕中可见范围的ViewHolder

ArrayList mCachedViews ---- 缓存滑动时即将与RecyclerView分离的ViewHolder,按子View的position或id缓存,默认最多存放2个

ViewCacheExtension mViewCacheExtension --- 开发者自行实现的缓存

RecycledViewPool mRecyclerPool --- ViewHolder缓存池,本质上是一个SparseArray,其中key是ViewType(int类型),value存放的是 ArrayList< ViewHolder>,默认每个ArrayList中最多存放5个ViewHolder。

二、缓存机制分析详解

RecyclerView滑动时会触发onTouchEvent#onMove,回收及复用ViewHolder在这里就会开始。我们知道设置RecyclerView时需要设置LayoutManager,LayoutManager负责RecyclerView的布局,包含对ItemView的获取与复用。以LinearLayoutManager为例,当RecyclerView重新布局时会依次执行下面几个方法:

onLayoutChildren():对RecyclerView进行布局的入口方法

fill(): 负责对剩余空间不断地填充,调用的方法是layoutChunk()

layoutChunk():负责填充View,该View最终是通过在缓存类Recycler中找到合适的View的

上述的整个调用链:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是从RecyclerView的回收机制实现类Recycler中获取合适的View,

下面主要就来从看这个Recycler#getViewForPosition()的实现。

  1. @NonNull 
  2. public View getViewForPosition(int position) { 
  3.     return getViewForPosition(position, false); 
  4. View getViewForPosition(int position, boolean dryRun) { 
  5.     return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView; 

他们都会执行tryGetViewHolderForPositionByDeadline函数,继续跟进去:

//根据传入的position获取ViewHolder

  1. ViewHolder tryGetViewHolderForPositionByDeadline(int position, 
  2.         boolean dryRun, long deadlineNs) { 
  3.     ...省略     
  4.     boolean fromScrapOrHiddenOrCache = false
  5.     ViewHolder holder = null
  6.     //预布局 属于特殊情况 从mChangedScrap中获取ViewHolder 
  7.     if (mState.isPreLayout()) { 
  8.         holder = getChangedScrapViewForPosition(position); 
  9.         fromScrapOrHiddenOrCache = holder != null
  10.     } 
  11.     if (holder == null) { 
  12.         //1、尝试从mAttachedScrap中获取ViewHolder,此时获取的是屏幕中可见范围中的ViewHolder 
  13.         //2、mAttachedScrap缓存中没有的话,继续从mCachedViews尝试获取ViewHolder 
  14.         holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun); 
  15.      ...省略 
  16.     } 
  17.     if (holder == null) { 
  18.         final int offsetPosition = mAdapterHelper.findPositionOffset(position); 
  19.         ...省略 
  20.         final int type = mAdapter.getItemViewType(offsetPosition); 
  21.         //如果Adapter中声明了Id,尝试从id中获取,这里不属于缓存 
  22.         if (mAdapter.hasStableIds()) { 
  23.             holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), 
  24.                     type, dryRun); 
  25.         } 
  26.         if (holder == null && mViewCacheExtension != null) { 
  27.             3、从自定义缓存mViewCacheExtension中尝试获取ViewHolder,该缓存需要开发者实现 
  28.             final View view = mViewCacheExtension 
  29.                     .getViewForPositionAndType(this, position, type); 
  30.             if (view != null) { 
  31.                 holder = getChildViewHolder(view); 
  32.             } 
  33.         } 
  34.         if (holder == null) { // fallback to pool 
  35.             //4、从缓存池mRecyclerPool中尝试获取ViewHolder 
  36.             holder = getRecycledViewPool().getRecycledView(type); 
  37.             if (holder != null) { 
  38.                 //如果获取成功,会重置ViewHolder状态,所以需要重新执行Adapter#onBindViewHolder绑定数据 
  39.                 holder.resetInternal(); 
  40.                 if (FORCE_INVALIDATE_DISPLAY_LIST) { 
  41.                     invalidateDisplayListInt(holder); 
  42.                 } 
  43.             } 
  44.         } 
  45.         if (holder == null) { 
  46.             ...省略 
  47.           //5、若以上缓存中都没有找到对应的ViewHolder,最终会调用Adapter中的onCreateViewHolder创建一个 
  48.             holder = mAdapter.createViewHolder(RecyclerView.this, type); 
  49.         } 
  50.     } 
  51.     boolean bound = false
  52.     if (mState.isPreLayout() && holder.isBound()) { 
  53.         holder.mPreLayoutPosition = position; 
  54.     } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) { 
  55.         final int offsetPosition = mAdapterHelper.findPositionOffset(position); 
  56.         //6、如果需要绑定数据,会调用Adapter#onBindViewHolder来绑定数据 
  57.         bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs); 
  58.     } 
  59.     ...省略 
  60.     return holder; 

通过mAttachedScrap、mCachedViews及mViewCacheExtension获取的ViewHolder不需要重新创建布局及绑定数据;通过缓存池mRecyclerPool获取的ViewHolder不需要重新创建布局,但是需要重新绑定数据;如果上述缓存中都没有获取到目标ViewHolder,那么就会回调Adapter#onCreateViewHolder创建布局,以及回调Adapter#onBindViewHolder来绑定数据

总结

RecyclerView 滑动场景下的回收复用涉及到的结构体两个:

 

 

来源: Android开发编程内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯