RecyclerView的布局原理及四级缓存-创新互联

在Android应用开发过程中,只要是涉及到列表类的数据加载,RecyclerView的使用都是必不可少的。那么RecyclerView有哪些值得我们借鉴的地方呢?让我们来一探究竟。

让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:主机域名网站空间、营销软件、网站建设、玉环网站维护、网站推广。一、测量和布局: RecyclerView测绘布局有三步,分别为start,layout和animation。对应的方法为dispatchLayoutStep1()、dispatchLayoutStep2()、dispatchLayoutStep3()。 

具体看源码,首先,我们先进行开始测绘布局前的准备工作,从recyclerView的setLayoutManager开始,从这里可以看出主要做了两件事情,一是判断当前的RecyclerView有无依赖的LayoutManager,如果有就清除掉。二是判断当前的LayoutManager是否依赖在了其他的RecyclerView上,如果有就直接抛出异常

   if (mLayout != null) {
            mRecycler.clear();
            if (mIsAttached) { //移除依赖
                mLayout.dispatchDetachedFromWindow(this, mRecycler);
            }
            mLayout.setRecyclerView(null);
            mLayout = null;
        }else{
            mRecycler.clear();
        }

        if (layout != null) {
            if (layout.mRecyclerView != null) {
                throw new IllegalArgumentException("LayoutManager " + layout
                        + " is already attached to a RecyclerView:"
                        + layout.mRecyclerView.exceptionLabel());
            }
            mLayout.setRecyclerView(this);
            if (mIsAttached) {
                mLayout.dispatchAttachedToWindow(this);
            }
        }

紧接着,由于RecyclerView继承的是ViewGroup,所以他的测绘布局动作也是我们重要看的。首先看onMeasure()测量方法。这里主要做了2件事情,

1:在某些极端情况下计算出尽可能合理的宽高值,进行兜底的操作

2:开启测量,布局的阶段,主要是dispatchLayoutStep2方法。此方法里面主要进行了item的布局工作,其中,至关重要的一个方法是执行了RecyclerView的onLayoutChildren方法,LinearLayoutManager,GridLayoutManager等布局管理器会实现此方法,进行具体的布局逻辑

@Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        //1:layoutManager 若为空,则无法进行测量,这时候会通过默认方法,尽可能的给出准确的尺寸
        if (mLayout == null) {
            defaultOnMeasure(widthSpec, heightSpec);
            return;
        }

        //开启自动测量
        if (mLayout.isAutoMeasureEnabled()) {
            final int widthMode = MeasureSpec.getMode(widthSpec);
            final int heightMode = MeasureSpec.getMode(heightSpec);

            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);

            final boolean measureSpecModeIsExactly =
                    widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY;
            if (measureSpecModeIsExactly || mAdapter == null) {
                return;
            }

            //这里主要对需要做动画的item进行收集和整理,完成后会把mState.mLayoutStep赋值成 
            //STEP_LAYOUT
            if (mState.mLayoutStep == State.STEP_START) {
                dispatchLayoutStep1();
            }

            //开始测量,并布局列表上的item,从而期望能够计算出RecyclerView的宽高
            dispatchLayoutStep2();

            //如果RecyclerView没有准确的宽高,并且至少有一个item也没有固定的宽高,则对再走一 
            //遍。 dispatchLayoutStep2(),进行更加准确的测量,从而能够得出RecyclerView的宽 
            //高。从这里我们也可以看出,在实际开发过程中尽肯能的对RecyclerView的宽高设置为精确 
            //的值。这里这行完成后,状态会被赋值成STEP_ANIMATIONS,开始第3阶段
            if (mLayout.shouldMeasureTwice()) {
                mLayout.setMeasureSpecs(
                        MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
                        MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
                mState.mIsMeasuring = true;
                dispatchLayoutStep2();
                // now we can get the width and height from the children.
                mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
            }
        } 
    }

最后,测量完成结束,会走到onLayout()回调中,如果前面没有开启自动测量,这里会再重新走一次dispatchLayoutStep1和2,再执行dispatchLayoutStep3,dispatchLayoutStep3里主要进行了动画执行的逻辑。

// onLayout的dispatchLayout()方法
 void dispatchLayout() {
        if (mState.mLayoutStep == State.STEP_START) {
            dispatchLayoutStep1();
            mLayout.setExactMeasureSpecsFrom(this);
            dispatchLayoutStep2();
        } else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()
                || mLayout.getHeight() != getHeight()) {
            // First 2 steps are done in onMeasure but looks like we have to run 
            //again due to
            // changed size.
            mLayout.setExactMeasureSpecsFrom(this);
            dispatchLayoutStep2();
        } else {
            // always make sure we sync them (to ensure mode is exact)
            mLayout.setExactMeasureSpecsFrom(this);
        }
        dispatchLayoutStep3();
    }
二、四级缓存

1:第一级缓存,不需要重新bindViewHolder。ArrayListmAttachedScrap; 保存的是屏幕上没有任何变化的ViewHolder, ArrayListmChangedScrap保存的是有变化ViewHolder,比如刷新了某个item那个此ViewHolder会被保存到mChangedScrap中

2:第二级缓存,不需要重新bindViewHolder,需要进行位置一致性校验,随着列表的上下滑动,被划出屏幕的ViewHolder就会储存到这里;可通过setItemCacheSize调整,默认大小为2;ArrayListmCacheViews;

3:自定义拓展View缓存,ViewCacheExtension mViewCacheExtension;可忽略

4:第四级缓存,当且仅当mCacheViews放不下的时候,会放入这个缓存里。根据viewType存取ViewHolder,可通过setRecycledViewPool调整,每个类型容量默认为5;RecycledViewPool mRecyclerPool;

三、复用机制

LayoutManager每次向列表上填充item的时候,会向Recycler索取ViewHolder优先级非别为mAttachScrp和mChangedScrp(屏幕内的ViewHolder,不需要重新绑定数据),mCacheViews(滑出屏幕的ViewHolder,也是不需要重新进行数据绑定,需要进行位置一致性校验,判断滑出屏幕的ViewHolder是否和需要现在重新放置的ViewHolder位置一致)和mRecyclerPool(需要重新进行数据绑定)。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网页标题:RecyclerView的布局原理及四级缓存-创新互联
标题链接:http://cdiso.cn/article/ddiccg.html

其他资讯