RecycleView原理分析

在面试中经常会遇见面试RecycleView的,RecycleView源代码及其复杂,想要回答好真的很困难,下面我就说一下我的理解。
先说RecycleView的用法。
1、设置一个LayoutManager 用于设置布局相关。
2、设置Adapter 用于将布局和数据进行绑定。
3、可以设置显示动画(这个是非必选)。
4、可以设置RecycleView的间隔(这个也是非必选)。

RecycleView说到底也只是一个自定义ViewGroup。所以先看一下onMeasure()是如何测量的。
onMeasure
首先会判断是否传入LayoutManager,如果没有则直接测量自身大小,如果自身大小确定,则显示自身大小否则不会显示大小因为它没有测量子view。
如果大小确定直接调用mLayoutManager的onMeasure方法去测量RecycleView的高,否则dispatchLayoutStep2方法进行测量并且布局。
onLayout
在这里会调用dispathLayout方法,这个里面仍然会dispathLayoutStep2这个方法。
在dispathLayoutStep2会接着调用 mLayout.onLayoutChildren()方法,不同的LayoutManager有不同的onLayoutChildren方法,这里分析LinearLayoutManager的onLayoutChildren()方法。
onLayoutChildren方法会调用fill方法对子view布局测量,在fill里面会先调用layoutChunk方法对子view进行布局和测量,然后fill会计算剩余的空间。layoutChunk会从缓存里获取到一个view,然后测量这个itemview的大小,并且确定itemview位置。
onDraw
会调用itemDecoration的onDraw方法画item间隔。

关于RecycleView的缓存
RecycleView之所以这么厉害,Recycler了。
RV主要实现了ViewHolder的缓存以及复用。核心代码在Recycler中完成。
里面主要分为四个部分。
第一个部分是scrap部分,当调用notifyXXX相关的代码的时候会将当前屏幕的ViewHolder缓存到scrap List数组中。

第二部分cacheViews数组,默认是2个,如果数组满了,按照FIFO的规则移除ViewHolder,通常情况下刚移除屏幕的viewholder并不会马上删除。而是存在cacheViews数组中。

第三部分ViewCacheExtsension 自定义的缓存策略一般用的比较少,也不建议用。

第四部分RecycleViewPool 也是缓存屏幕外的ViewHolder,当CachedView数据已满,则会将CachedView抛弃的ViewHolder交给RecycleViewPool,但是ViewHolder的数据会被删除,再次调用的话需要调用onBinderViewHolder绑定数据,这和ListView使用ViewHolder复用convertView道理一致。

取出缓存
从Recycler里面按照顺序先获取Scrap里面的缓存,之后是cacheview里面的 在之后是cacheViewExtension里面的,最后是从RecycleViewPool里获取数据。如果都获取不到,则会调用Adapter的createViewHolder()方法生成一个ViewHolder。

当然也可以自定义ItemView的动画,以及添加ItemDecortion每一个item的间隔。

 rv.addItemDecoration(new RecyclerView.ItemDecoration() {
            private int mDividerHeight = 10;
            @Override
            public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
                super.onDraw(c, parent, state);
                int childCount = parent.getChildCount();
                for ( int i = 0; i < childCount; i++ ) {
                    View view = parent.getChildAt(i);

                    int index = parent.getChildAdapterPosition(view);
                    //第一个ItemView不需要绘制
                    if ( index == 0 ) {
                        continue;
                    }

                    float dividerTop = view.getTop() - mDividerHeight;
                    float dividerLeft = parent.getPaddingLeft();
                    float dividerBottom = view.getTop();
                    float dividerRight = parent.getWidth() - parent.getPaddingRight();

                    c.drawRect(dividerLeft,dividerTop,dividerRight,dividerBottom,mPaint);
                }
            }

            /**
             *
             * @param outRect
             * @param view
             * @param parent
             * @param state
             *
             * 可以通过 outRect.set(l,t,r,b)  来指定 itemview的paddingLeft,paddingTop, paddingRight, paddingBottom
             */
            @Override
            public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
                // TODO Auto-generated method stub
                super.getItemOffsets(outRect, view, parent, state);

                //第一个ItemView不需要在上面绘制分割线
                if (parent.getChildAdapterPosition(view) != 0){
                    //这里直接硬编码为1px
                    outRect.top = mDividerHeight;
                }
            }
        });

        //添加动画,我们可以模拟DefaultItemAnimator 定义自己的动画
        rv.setItemAnimator(new DefaultItemAnimator());
        findViewById(R.id.btn_add).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                list.add(2,"add");
                rvAdapter.notifyItemInserted(2);
            }
        });

        findViewById(R.id.btn_delete).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                list.remove(2);
                rvAdapter.notifyItemRemoved(2);
            }
        });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecycleView 是一个用于在 Android 应用中展示大量数据的高效视图组件。它可以用于显示列表、网格或瀑布流等不同类型的布局,并支持高度的重用和回收。这个组件可以大大提高应用程序的性能,因为它只会在屏幕上显示可见项,而不是将所有数据一次性加载到内存中。 使用 RecycleView,您需要创建一个适配器(Adapter)来将数据绑定到视图上,并且可以自定义视图的外观和交互。您可以使用默认的适配器(如 ArrayAdapter)或自定义适配器来满足特定的需求。 以下是一个示例代码,演示如何使用 RecycleView 在一个简单的列表中显示一组文本项: ```java public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> mData; public MyAdapter(List<String> data) { mData = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { String item = mData.get(position); holder.textView.setText(item); } @Override public int getItemCount() { return mData.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView textView; public ViewHolder(View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值