RecyclerView 的源码浅析

RecyclerView 是 materials design 中的组件之一,相应的还有CardView 等。从名字看,它主要的特点就是复用。我们之前用的 ListView 也可以复用。但是 RecyclerView 提供了一个耦合度更低的方式来复用 ViewHolder,将实体的内容交给用户,而将缓存的复用、管理维护以及各种动画效果,做了封装。

本文主要分析 RecyclerView 的缓存机制,布局管理器以及 Adapter 的实现方式。

继承关系

java.lang.Object
 ↳  android.view.View
  ↳ android.view.ViewGroup
    ↳   android.support.v7.widget.RecyclerView

从中可以看出 RecyclerView 作为一个全新组件,完全重写了 ViewGroup,并不是对 ListView 的扩展。

构造方法:

主要作用如下:
1. 初始化 AdapterManager
2. 初始化 ChildrenHelper(子 view 的主要管理器)
3. 初始化动画的监听
4. 从属性获取 layoutManager 的名字,并通过反射创建 LayoutManager对象

ViewHolder 和 Adapter

ViewHolderAdapterRecyclerView 的内部抽象类,对外提供接口,将内容的创建过程交给用户,而将 view 的复用、管理、缓存等操作封装起来。

其实对于 ListView,也可以实现这种设计方式。请参考我的另一篇:
《ListView 优化篇:从 BaseAdapter 到 BaseViewHolder》

ListView 实现 Recycler.Adapter 的代码如下:

public abstract class DefaultAdapter<T> extends BaseAdapter {
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        BaseViewHolder holder = null;
        if (convertView == null) {
            // 创建 ViewHolder
            holder = onCreateViewHolder(); 
        } else {
            holder = (BaseViewHolder) convertView.getTag();
        }

        T info = mDatas.get(position);
        // 绑定数据
        holder.onBindViewHolder(); 
        return holder.getContentView();
    }

    protected abstract void onCreateViewHolder(BaseViewHolder holder, T data);

}

布局管理器 LayoutManager

LayoutManager 的方法来看,它的主要作用是:

  1. 负责 RecyclerView 和子 View 的测量、布局并最终以特定的效果显示在界面
  2. 管理着动画。
  3. 管理各种 view 的存储
  4. 实现整个 RecyclerView 的滚动

下面是几个最具代表性的方法:

  • setRecyclerView 为 RecyclerView 设置测量规则,通过这种方式设置的规则都是 MeasureSpec.EXACTLY,临时值
  • setMeasuredDimensionFromChildren 根据子View的大小,设置自身大小
  • endAnimation 结束动画
  • addView 添加子 view
  • removeView 移除子 view
  • findViewByPosition 查找view

缓存管理机制

RecyclerView 通过 ViewHolder 展现子视图,其中维护了一个二级缓存,滑出界面的 ViewHolder 会暂时放到 cache 结构中,而从 cache 结构中移除的ViewHolder,则会放到一个叫做 RecycledViewPool 的循环缓存池中。RecycledViewPoolViewHolder 还可以被多个 RecyclerView 共享,以提升性能。其中,cache 默认存 2 个,RecycledViewPool 默认存 5 个。对于二级缓存池中的 holder 对象,根据 viewType 进行严格分类,不同类型的 viewType 之间的缓存互不影响。

以下是 RecycledViewPool 的原理:

public static class RecycledViewPool {
    // 根据 viewType 保存的被废弃的 ViewHolder 集合,以便下次使用
    private SparseArray<ArrayList<ViewHolder>> mScrap = new SparseArray<ArrayList<ViewHolder>>();
    // 各种 viewType 对应的最大缓存数
    private SparseIntArray mMaxScrap = new SparseIntArray();
    // 默认缓存 5 个
    private static final int DEFAULT_MAX_SCRAP = 5;

    /** * 设置最大缓存数量 说明:如果有多余,从顶部移除多余的对象 * * @param viewType * @param max */
    public void setMaxRecycledViews(int viewType, int max) {
        mMaxScrap.put(viewType, max);
        final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
        if (scrapHeap != null) {
            while (scrapHeap.size() > max) {
                scrapHeap.remove(scrapHeap.size() - 1);
            }
        }
    }

    /** * 获取缓存对象 说明:从顶部获取,获取后移除 * * @param viewType * @return */
    public ViewHolder getRecycledView(int viewType) {
        final ArrayList<ViewHolder> scrapHeap = mScrap.get(viewType);
        if (scrapHeap != null && !scrapHeap.isEmpty()) {
            final int index = scrapHeap.size() - 1;
            final ViewHolder scrap = scrapHeap.get(index);
            scrapHeap.remove(index);
            return scrap;
        }
        return null;
    }

    public void putRecycledView(ViewHolder scrap) {
        final int viewType = scrap.getItemViewType();
        final ArrayList scrapHeap = getScrapHeapForType(viewType);
        if (mMaxScrap.get(viewType) <= scrapHeap.size()) {
            return;
        }
        scrap.resetInternal();
        scrapHeap.add(scrap);
    }

    /** * 根据 viewType 获取对应缓存池 说明:如果不存在,则创建 * * @param viewType * @return */
    private ArrayList<ViewHolder> getScrapHeapForType(int viewType) {
        ArrayList<ViewHolder> scrap = mScrap.get(viewType);
        if (scrap == null) {
            scrap = new ArrayList<>();
            mScrap.put(viewType, scrap);
            if (mMaxScrap.indexOfKey(viewType) < 0) {
                mMaxScrap.put(viewType, DEFAULT_MAX_SCRAP);
            }
        }
        return scrap;
    }
}
    原文作者:SvenHe
    原文地址: https://blog.csdn.net/anydrew/article/details/50936735
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞