Android RecyclerView绘制页面的源码分析<一>

2022-02-17  本文已影响0人  没有了遇见

RecyclerView 可以让您轻松高效地显示大量数据。您提供数据并定义每个列表项的外观,而 RecyclerView 库会根据需要动态创建元素。

顾名思义,RecyclerView 会回收这些单个的元素。当列表项滚动出屏幕时,RecyclerView 不会销毁其视图。相反,RecyclerView 会对屏幕上滚动的新列表项重用该视图。这种重用可以显著提高性能,改善应用响应能力并降低功耗。

关键对象和方法

Demo:

class RecyclerViewActivity : AppCompatActivity() {
    var binding: ActivityRecyclerviewBinding? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView<ActivityRecyclerviewBinding>(this, R.layout.activity_recyclerview)
        initView()
    }

    private fun initView() {
        var mAdapter = DemoAdapter(this)
        
        //设置LayoutManager
        binding!!.rvContent.layoutManager = LinearLayoutManager(this)
        //设置 Adapter
        binding!!.rvContent.adapter = mAdapter
        var listData=ArrayList<String>()
        listData.add("Android新控件")
        listData.add("循环效果2:循环")
        listData.add("Android")
        listData.add("MotionLayout")
        listData.add("Banner")
        listData.add("循环效果2")
        listData.add("Android新控件之MotionLayout实现Banner循环效果2:循环")
        //刷新数据
        mAdapter.addItems(listData)
    }

    // 自定义Adapter
    class DemoAdapter(mContext: Context) : RecyclerView.Adapter<DemoViewHolder>() {
        var mContext: Context? = null
        var listData=ArrayList<String>()
        init {
            this.mContext = mContext
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DemoViewHolder {
            var view = LayoutInflater.from(mContext).inflate(R.layout.item_demo, parent, false)
            var viewHolder = DemoViewHolder(view)
            return viewHolder
        }

        override fun onBindViewHolder(holder: DemoViewHolder, position: Int) {
           var mHolder=  holder
            mHolder.getTextView().text=listData.get(position)
        }

        override fun getItemCount(): Int {
           return  listData.size
        }

        fun addItems(items:ArrayList<String>){
            listData.addAll(items)
            //刷新数据
            notifyDataSetChanged()
        }

    }
    // 自定义Holder
    class DemoViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        var rootView:View?=null
        init {
            rootView = view
        }
        fun getTextView():TextView{
           var tvContent= rootView!!.findViewById<TextView>(R.id.tv_content)
            return tvContent
        }
    }
}

源码分析

看到简单的Demo LayoutManager 管理了RecyclerView的布局,Adapter 填充了RecycerView子条目和绑定子条目的数据

所以咱们从Adapter 绑定数据数据看RecyceView的整体数据添加和页面布局

1.设置LayoutManager

LayoutManager.png
   /**
     * Set the {@link LayoutManager} that this RecyclerView will use.
     *
     * <p>In contrast to other adapter-backed views such as {@link android.widget.ListView}
     * or {@link android.widget.GridView}, RecyclerView allows client code to provide custom
     * layout arrangements for child views. These arrangements are controlled by the
     * {@link LayoutManager}. A LayoutManager must be provided for RecyclerView to function.</p>
     *
     * <p>Several default strategies are provided for common uses such as lists and grids.</p>
     *
     * @param layout LayoutManager to use
     */

// 设置 LayoutManager 配置布局的管理器
    public void setLayoutManager(@Nullable LayoutManager layout) {
        if (layout == mLayout) {
            return;
        }
 // 设置停止滑动
        stopScroll();
        // TODO We should do this switch a dispatchLayout pass and animate children. There is a good
        // chance that LayoutManagers will re-use views.
        if (mLayout != null) {
            // end all running animations
            if (mItemAnimator != null) {
                mItemAnimator.endAnimations();
            }
            mLayout.removeAndRecycleAllViews(mRecycler);
            mLayout.removeAndRecycleScrapInt(mRecycler);
            mRecycler.clear();

            if (mIsAttached) {
                mLayout.dispatchDetachedFromWindow(this, mRecycler);
            }
            mLayout.setRecyclerView(null);
            mLayout = null;
        } else {
            mRecycler.clear();
        }
        // this is just a defensive measure for faulty item animators.
        mChildHelper.removeAllViewsUnfiltered();
        mLayout = layout;
        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);
            }
        }
        mRecycler.updateViewCacheSize();
        requestLayout();
    }

2.设置Adapter适配器

设置适配器.png

2.1配置数据

image.png

2.2 设置数据观察者 RecyclerViewDataObserver mObserver

image.png
设置数据观察者.png

2.3 notifyDataSetChanged 添加数据以及数据刷新

    Adapter.notifyDataSetChanged() 

2.4 刷新数据 调用到 AdapterDataObservable mObservable 数据更新了

刷新.png

2.5 RecyclerView Adapter的mObservers 调用注册的 mObservers中的RecycrViewDataObserver

RecycrViewDataObserver.png

2.5.1 RecycrViewDataObserver (设置Adapter的时候注册的数据更新的观察者)

设置观察者.png

2.5.2 RecycrViewDataObserver (设置Adapter的时候注册的数据更新的观察者)


RecycrViewDataObserver .png

2.6 更新或者添加数据 RecycrViewDataObserver 收到监听更新布局

调用重绘布局.png

2.7 重新 布局页面

onLayout.png

2.8 重新 布局页面 执行 dispatchLayoutStep2()

dispatchLayoutStep2.png

2.9 LayoutManager 执行 onLayoutChildren() 布局 子布局

onLayoutChildren.png

2.10 LayoutManager 是第一步试着的LayoutManager

LayoutManager .png

2.11 LayoutManager 布局子条目的位置

onLayoutChildren.png

总结:

RecyelerView 绘制的主要方法就是设置LayoutManager Adapter RecyclerViewDataObserver dispatchLayout() dispatchLayoutStep2() mLayout.onLayoutChildren(mRecycler, mState); 主要是这几个对象以及方法 执行了 RecyclerView的刷新以及布局的流程 . LayoutManager 负责布局Item的位置 Adapter 负责创建和填充数据 RecyclerViewDataObserver 监听 数据的更新 dispatchLayout () dispatchLayoutStep2() 调用LayoutManager 的onLayoutChildren布局数据

写作不易,欢迎点赞

参考文献

1.RecyclerView Google Developer概览

2.Demo源码地址

上一篇 下一篇

猜你喜欢

热点阅读