本文转载自微信公众号「Android开发编程」,作者Android开发编程。转载本文请联系Android开发编程公众号。
创新互联公司为企业级客户提高一站式互联网+设计服务,主要包括网站设计制作、网站建设、成都app软件开发、成都微信小程序、宣传片制作、LOGO设计等,帮助客户快速提升营销能力和企业形象,创新互联各部门都有经验丰富的经验,可以确保每一个作品的质量和创作周期,同时每年都有很多新员工加入,为我们带来大量新的创意。
学习源码,研究源码编程思想,是程序开发者进阶的必经之路
大家都知道RecyclerView有回收复用机制,那么回收复用机制是如何作用的?
今天我们就用源码来讲解,一起学习
RecyclerView是通过内部类Recycler管理的缓存,那么Recycler中缓存的是什么?我们知道RecyclerView在存在大量数据时依然可以滑动的如丝滑般顺畅,而RecyclerView本身是一个ViewGroup,那么滑动时避免不了添加或移除子View(子View通过RecyclerView#Adapter中的onCreateViewHolder创建),如果每次使用子View都要去重新创建,肯定会影响滑动的流 畅性,所以RecyclerView通过Recycler来缓存的是ViewHolder(内部包含子View),这样在滑动时可以复用子View,某些条件下还可以复用子View绑定的数据。所以本质上缓存是为了减少重复绘制View和绑定数据的时间,从而提高了滑动时的性能
- public final class Recycler {
- final ArrayList
mAttachedScrap = new ArrayList<>(); - ArrayList
mChangedScrap = null; - final ArrayList
mCachedViews = new ArrayList (); - private final List
- mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
- private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
- int mViewCacheMax = DEFAULT_CACHE_SIZE;
- RecycledViewPool mRecyclerPool;
- private ViewCacheExtension mViewCacheExtension;
- static final int DEFAULT_CACHE_SIZE = 2;
Recycler缓存ViewHolder对象有4个等级,优先级从高到底依次为:
1、ArrayList mAttachedScrap --- 缓存屏幕中可见范围的ViewHolder
2、ArrayList mCachedViews ---- 缓存滑动时即将与RecyclerView分离的ViewHolder,按子View的position或id缓存,默认最多存放2个
3、ViewCacheExtension mViewCacheExtension --- 开发者自行实现的缓存
4、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()的实现。
- @NonNull
- public View getViewForPosition(int position) {
- return getViewForPosition(position, false);
- }
- View getViewForPosition(int position, boolean dryRun) {
- return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView;
- }
他们都会执行tryGetViewHolderForPositionByDeadline函数,继续跟进去:
//根据传入的position获取ViewHolder
- ViewHolder tryGetViewHolderForPositionByDeadline(int position,
- boolean dryRun, long deadlineNs) {
- ...省略
- boolean fromScrapOrHiddenOrCache = false;
- ViewHolder holder = null;
- //预布局 属于特殊情况 从mChangedScrap中获取ViewHolder
- if (mState.isPreLayout()) {
- holder = getChangedScrapViewForPosition(position);
- fromScrapOrHiddenOrCache = holder != null;
- }
- if (holder == null) {
- //1、尝试从mAttachedScrap中获取ViewHolder,此时获取的是屏幕中可见范围中的ViewHolder
- //2、mAttachedScrap缓存中没有的话,继续从mCachedViews尝试获取ViewHolder
- holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
- ...省略
- }
- if (holder == null) {
- final int offsetPosition = mAdapterHelper.findPositionOffset(position);
- ...省略
- final int type = mAdapter.getItemViewType(offsetPosition);
- //如果Adapter中声明了Id,尝试从id中获取,这里不属于缓存
- if (mAdapter.hasStableIds()) {
- holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
- type, dryRun);
- }
- if (holder == null && mViewCacheExtension != null) {
- 3、从自定义缓存mViewCacheExtension中尝试获取ViewHolder,该缓存需要开发者实现
- final View view = mViewCacheExtension
- .getViewForPositionAndType(this, position, type);
- if (view != null) {
- holder = getChildViewHolder(view);
- }
- }
- if (holder == null) { // fallback to pool
- //4、从缓存池mRecyclerPool中尝试获取ViewHolder
- holder = getRecycledViewPool().getRecycledView(type);
- if (holder != null) {
- //如果获取成功,会重置ViewHolder状态,所以需要重新执行Adapter#onBindViewHolder绑定数据
- holder.resetInternal();
- if (FORCE_INVALIDATE_DISPLAY_LIST) {
- invalidateDisplayListInt(holder);
- }
- }
- }
- if (holder == null) {
- ...省略
- //5、若以上缓存中都没有找到对应的ViewHolder,最终会调用Adapter中的onCreateViewHolder创建一个
- holder = mAdapter.createViewHolder(RecyclerView.this, type);
- }
- }
- boolean bound = false;
- if (mState.isPreLayout() && holder.isBound()) {
- holder.mPreLayoutPosition = position;
- } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
- final int offsetPosition = mAdapterHelper.findPositionOffset(position);
- //6、如果需要绑定数据,会调用Adapter#onBindViewHolder来绑定数据
- bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
- }
- ...省略
- return holder;
- }
通过mAttachedScrap、mCachedViews及mViewCacheExtension获取的ViewHolder不需要重新创建布局及绑定数据;通过缓存池mRecyclerPool获取的ViewHolder不需要重新创建布局,但是需要重新绑定数据;如果上述缓存中都没有获取到目标ViewHolder,那么就会回调Adapter#onCreateViewHolder创建布局,以及回调Adapter#onBindViewHolder来绑定数据
RecyclerView 滑动场景下的回收复用涉及到的结构体两个:
分享题目:Android架构师之深入理解RecyclerView复用和缓存机制详解
转载来于:http://www.gawzjz.com/qtweb/news29/197579.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联