【Android】RecyclerView回收复用机制

概述

RecyclerView 是 Android 中用于高效显示大量数据的视图组件,它是 ListView 的升级版本,支持更灵活的布局和功能。

我们创建一个RecyclerView的Adapter:

public class MyRecyclerView extends RecyclerView.Adapter<MyRecyclerView.MyHolder> {
   

    private List<String> strings;
    private Context context;

    public MyRecyclerView(List<String> strings, Context context) {
   
        this.strings = strings;
        this.context = context;
    }

    @NonNull
    @Override
    public MyRecyclerView.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
   

        View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
        MyRecyclerView.MyHolder viewHolder = new MyHolder(view);
        Log.d("MyRecyclerView", "onCreateViewHolder: ");
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyRecyclerView.MyHolder holder, int position) {
   
        holder.textView.setText("第" + position + "项");
        Log.d("MyRecyclerView", "onBindViewHolder: " + position);
    }

    @Override
    public int getItemCount() {
   
        return strings == null ? 0 : strings.size();
    }

    public class MyHolder extends RecyclerView.ViewHolder {
   
        private TextView textView;
        public MyHolder(@NonNull View itemView) {
   
            super(itemView);
            textView = itemView.findViewById(android.R.id.text1);
        }
    }
}

我们在onCreateViewHolder和onBindViewHolder都打印log。

onCreateViewHolder()会在创建一个新view的时候调用,onBindViewHolder()会在已存在view,绑定数据的时候调用。

我们来看一下运行时打印的log:

image-20241119212232289

在最开始加载view的时候,两个方法onCreateViewHolder()onBindViewHolder()都执行了,但是当我们上下滑动RecyclerView的时候,我们会发现只执行了onBindViewHolder()方法。所以说,RecyclerView并不是会一直重新创建View,而是会对view进行复用。

复用机制

当我们想去通过看源码去了解缓存复用机制的时候,我们要去想看源码的入口在哪里。上文我们提到是在滑动RecyclerView的时候进行了缓存复用,所以我们会想到去看 onTouchEvent 这个方法:

@Override
public boolean onTouchEvent(MotionEvent e) {
   
        ...
    case MotionEvent.ACTION_MOVE: {
   
        final int index = e.findPointerIndex(mScrollPointerId);
        if (index < 0) {
   
            Log.e(TAG, "Error processing scroll; pointer index for id "
                    + mScrollPointerId + " not found. Did any MotionEvents get skipped?");
            return false;
        }

        final int x = (int) (e.getX(index) + 0.5f);
        final int y = (int) (e.getY(index) + 0.5f);
        int dx = mLastTouchX - x;
        int dy = mLastTouchY - y;

        if (mScrollState != SCROLL_STATE_DRAGGING) {
   
            boolean startScroll = false;
            if (canScrollHorizontally) {
   
                if (dx > 0) {
   
                    dx = Math.max(0, dx - mTouchSlop);
                } else {
   
                    dx = Math.min(0, dx + mTouchSlop);
                }
                if (dx != 0) {
   
                    startScroll = true;
                }
            }
            if (canScrollVertically) {
   
                if (dy > 0) {
   
                    dy = Math.max(0, dy - mTouchSlop);
                } else {
   
                    dy = Math.min(0, dy + mTouchSlop);
                }
                if (dy != 0) {
   
                    startScroll = true;
                }
            }
            if (startScroll) {
   
                setScrollState(SCROLL_STATE_DRAGGING);
            }
        }

        if (mScrollState == SCROLL_STATE_DRAGGING) {
   
            mReusableIntPair[0] = 0;
            mReusableIntPair[1] = 0;
            if (dispatchNestedPreScroll(
                    canScrollHorizontally ? dx : 0,
                    canScrollVertically ? dy : 0,
                    mReusableIntPair, mScrollOffset, TYPE_TOUCH
            )) {
   
                dx -= mReusableIntPair[0];
                dy -= mReusableIntPair[1];
                // Updated the nested offsets
                mNestedOffsets[0] += mScrollOffset[0];
                mNestedOffsets[1] += mScrollOffset[1];
                // Scroll has initiated, prevent parents from intercepting
                getParent().requestDisallowInterceptTouchEvent(true);
            }

            mLastTouchX = x - mScrollOffset[0];
            mLastTouchY = y - mScrollOffset[1];

            if (scrollByInternal(
                    canScrollHorizontally ? dx : 0,
                    canScrollVertically ? dy : 0,
                    e)) {
   
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            if (mGapWorker != 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值