RecyclerView原理分析

RecyclerView


继承关系如下

public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {

RecyclerView内部重要的抽象类LayoutManager

LayoutManager的英文注释翻译

在RecyclerView的 layoutManager可以布局和定位ItemVIew,以及使用者看不见的item的回收策略,通过改变layoutManager,RecyclerView可以实现一个标准的垂直滚动的列表,统一网格,交错网格,水平滚动集合和更多。系统提供了几种通用的样式。

LayoutManager的作用

从上面的翻译可以看出,它的作用就是负责RecycleView对ItemView的测量和布局以及回收策略的实现

系统提供几种 LayoutManager通用样式分别为:

(1)LinearLayoutManager(线性布局管理器)

public class LinearLayoutManager extends RecyclerView.LayoutManager implements
        ItemTouchHelper.ViewDropHandler, RecyclerView.SmoothScroller.ScrollVectorProvider {

(2)GridLayoutManager(表格布局管理器)

public class GridLayoutManager extends LinearLayoutManager {}

(3)StaggeredGridLayoutManager (瀑布流布局管理器)

public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager implements
        RecyclerView.SmoothScroller.ScrollVectorProvider {}

绘制流程

RecyclerView的 onlayout和onMeasure,onDraw内部方法调用

由它的内部抽象类RecyclerView.LayoutManager实现,RecyclerView负责绘制所有decoration;ItemView的绘制由ViewGroup处理,RecyclerView不负责绘制itemVIew,并且是逐个执行的,也就是说执行完一个子控件的onMeasure和onlayout过程,在执行下一个。如下代码:


RecyclerView的onMeasure方法

  @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
             // mLayout测量过程 
            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
            if (mState.mLayoutStep == State.STEP_START) {                
                //mLayout布局过程
                dispatchLayoutStep2();
            }
           ......代码略
    }

看下方法:dispatchLayoutStep2()

 private void dispatchLayoutStep2() {
   ......代码略
        mLayout.onLayoutChildren(mRecycler, mState);
   ......代码略
    }

进入到onlayoutChildren方法

 @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { 
        ...if (mAnchorInfo.mLayoutFromEnd) {
           ...略
            fill(recycler, mLayoutState, state, false);
            // fill towards start
            fill(recycler, mLayoutState, state, false);
            ...略
        } else {
            ...略
            // fill towards end
            fill(recycler, mLayoutState, state, false);
            // fill towards start
            fill(recycler, mLayoutState, state, false);
            ...略

        }
...略
    }

onLayoutChildren确定布局锚点,以此为起点向开始和结束方向填充ItemView,至于填充即使在fill方法里了,这段代码做的工作 如下:
这里写图片描述

接下来进入到fill()方法,看看是如何填充的

 int fill(...) {
        //循环调用layoutChunk
        while (...) {
            layoutChunk(...);
         }   
    }

就是一些系列的判断循环调用layoutchunk方法,进入layoutchunk方法

  void layoutChunk(...) {
                addView(view);

    }

走到这里就是调用ViewGroup的addview方法了,添加View。
以上就是RecyclerView的onMeasure的方法里执行layoutManager的onMeasure和onlayout方法。


RecyclerView的onLayout方法

void dispatchLayout() {
    ...
    if (mState.mLayoutStep == State.STEP_START) {
        dispatchLayoutStep1();
        ...
        dispatchLayoutStep2();
    }
    dispatchLayoutStep3();
    ...
}

发现RecyclerView的layout方法也会执行dispatchLayoutStep()方法,就是也会走layoutManager的onMeasure和onlayout方法。

RecyclerView的layout和measure里都执行了layoutManager的测量和布局方法,那么是执行两边layoutManager的测量和布局方法,还是只执行一次呢?

在RecycleView’中的onMeasure中会判断如果RecycleView支持WRAP_CONTENT,先确定了子控件的大小及位置后,再由此设置RecyclerView的大小;如果是其它情况(测量模式为EXACTLY),子控件的measure及layout过程就会延迟至RecyclerView的layout过程


#####RecyclerView的onDraw方法#####


 @Override
    public void onDraw(Canvas c) {
        super.onDraw(c);

        final int count = mItemDecorations.size();
        for (int i = 0; i < count; i++) {
            mItemDecorations.get(i).onDraw(c, this, mState);
        }
    }

ItemDecoration是啥?
即使保存了ItemView四个方向的偏移量值,可以想象成padding,测量时itemView的itemDecoration保存的对应的偏移量的值也会被计算进去。

在measureChildWithMargins方法中调用获取itemDecoration
的值

public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
        ...
        final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);
       ...
            child.measure(widthSpec, heightSpec);
        }
    }

如下就是itemDecoration的偏移量大小+itemVIew自身的大小

这里写图片描述


滑动过程流程分析

分析Recycle的

public boolean onTouchEvent(MotionEvent e) { 
    ...
    switch (action) {
        ...
        case MotionEvent.ACTION_MOVE: {
         //手指滑动距离>滑动阀值 则为SCROLL_STATE_DRAGGING
         //进行滚动
            if (mScrollState == SCROLL_STATE_DRAGGING) {

            scrollByInternal();
        } 
        break;
        ...
        case MotionEvent.ACTION_UP: {
        //手指抬起后 获取之前的滑动距离和时间算出平均速度,由
        //VelocityTracker实现的,然后传入filing进行滚动 
            ...
           此处执行fling()方法 
        } break;
        ...
    }
    ...
}

scrollByInternal()和fling()方法都会调用相应的layoutManager的子类的,比如使用的是LinearLayoutManager,则调用LinearLayoutManager的scrollBy方法

int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
    ...
    //此处调用fill方法 进行addview了
    final int consumed = mLayoutState.mScrollingOffset
            + fill(recycler, mLayoutState, state, false);
    ...
    //开始平移View
    mOrientationHelper.offsetChildren(-scrolled);
}

综上述分析就是: Scroller每次计算的滑动偏移量是很小的一部分,而RecyclerView就会根据这个偏移量,确定是平移ItemView,还是除了平移还需要再创建新ItemView
如下图:
这里写图片描述


Recycle(回收机制)


作用:RecycleView的回收机制由它实现
结构:scrapped、cached和exCached集合定义在RecyclerView.Recycler中,
内部集合
(1)scrapped:存放 删除的ItemView
(2)cached:以及缓存和二级缓存 结合默认大小为2
(3)exCached:默认没有实现,需要自己实现
(4)recycled:在RecyclerView.RecycledViewPool中,用于区分Item,用ItemType,本身是个map集合,RecyclerView.RecycledViewPool可以实现在不同的RecyclerView之间共享ItemView,只要为这些不同RecyclerView设置同一个RecyclerView.RecycledViewPool就可以了。
使用的地方:在fill时判断:
首先判断集合cached是否満了,如果已満就从cached集合中移出一个到recycled集合中去,再把新的ItemView添加到cached集合;如果不満就将ItemView直接添加到cached集合。
最后exCached集合是我们自己创建的,所以添加删除元素也要我们自己实现。


数据集、动画


(1)RecycleView对数据集有四种操作:ADD、REMOVE、UPDATE、MOVE,封装在了AdapterHelper.UpdateOp

  static class UpdateOp {

        static final int ADD = 1;

        static final int REMOVE = 1 << 1;

        static final int UPDATE = 1 << 2;

        static final int MOVE = 1 << 3;

        static final int POOL_SIZE = 30;

(2)RecyclerView.RecyclerViewDataObserver.triggerUpdateProcessor()执行时,根据这个等待队列中的信息,对所有子控件重新测量、布局并绘制且执行动画。以上就是我们调用Adapter.notifyItemXXX()系列然后调用RecyclerView.onLayout()会随后调用执行onLayout中的dispatchLayoutStep1()初始化数据,dispatchLayoutStep2(),测量和布局,dispatchLayoutStep3就是添加动画。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: RecyclerView是一个Android的UI组件,用于在列表或网格中显示大量数据。它可以自动回收不可见的视图,提高性能,并且支持多种布局管理器,如线性布局、网格布局和瀑布流布局等。开发者可以通过适配器来提供数据,并且可以自定义视图的外观和交互。 ### 回答2: RecyclerView是Android平台上的一个强大的视图容器,用于展示大量数据的列表或网格布局。它是Android支持库中的一个组件,提供了比ListView更灵活和高效的方式来展示和处理数据。 相比于ListView,RecyclerView具有更好的性能和扩展性。它采用了ViewHolder模式和布局管理器的设计思想,使得列表中的每个列表项都可以重用,并且只加载可见区域的列表项,从而减少了内存消耗和渲染时间。通过适配器(Adapter)和数据集(Dataset)的结合,RecyclerView可以很方便地处理数据的变化和更新,实现了数据的分离和重用。 RecyclerView的布局管理器(Layout Manager)提供了多种布局方式,如线性布局、网格布局、瀑布流布局等,开发者可以根据需求选择合适的布局方式来展示数据。此外,RecyclerView还支持添加分割线、动画效果等,使得列表项具有更加丰富和炫酷的展示效果。 除了基本的数据展示功能,RecyclerView还提供了交互事件的处理接口,如点击、长按、滑动、拖拽等,这使得开发者可以方便地处理用户的交互操作,并实现一些复杂的列表交互效果。 总之,RecyclerView是Android开发中常用的一个组件,它通过适配器、布局管理器和数据集的组合,提供了高效、灵活和可扩展的数据展示和交互功能,可以满足各种复杂列表布局和需求。 ### 回答3: RecyclerView是一个在安卓开发中常用的控件,用于展示大量数据。它是ListView的升级版本,相比ListView,RecyclerView可以更灵活地管理和展示数据。 首先,RecyclerView使用了ViewHolder模式来优化视图的复用,减少了内存的占用和视图的创建。通过ViewHolder模式,可以减少findViewById方法的调用次数,提高了列表的滑动性能。 其次,RecyclerView通过LayoutManager来管理视图的布局方式。它提供了多种布局方式,如线性布局、网格布局、瀑布流布局等,开发者可以根据需求自由选择。布局方式的灵活性使开发者可以更好地适应不同的展示效果。 另外,RecyclerView支持动画效果的添加和删除。通过添加ItemAnimator,可以在数据增加或删除时给列表添加动画效果,使用户体验更加丰富。 除此之外,RecyclerView还提供了各种辅助类和接口,如ItemDecoration、ItemTouchHelper等,可以方便地添加分割线、滑动删除等功能。 总的来说,RecyclerView是一种非常强大的控件,适用于展示大量数据的场景。它通过ViewHolder模式、LayoutManager和动画效果等特性,提高了列表的性能和用户体验,为开发者在安卓应用的开发中带来了便利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值