1. Problem scenario

CoordinatorLayout> <AppBarLayout> <RecycleView> </RecycleView> </AppBarLayout> </ConstraintLayout>Copy the code

RecycleView ViewHoder reuse failure, causing CPU consumption, item reach a certain number of items will cause the OOM page appear lag

2. Problem principle

RecycleView ViewHoder Reuse problem the first time we should think is; The measMeasureChild module has an onMeasureChild value of UNSPECIFIED and RecycleView. It has an onMeasureChild value of UNSPECIFIED and RecycleView. It has an onMeasureChild value of UNSPECIFIED and RecycleView.

 @Override
    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
        child.measure(parentWidthMeasureSpec, parentHeightMeasureSpec);
    }

Copy the code

ParentHeightMeasureSpec has been set as MeasureSpec. It has an UNSPECIFIED measure mode. The CoordinatorLayout onMeasure has an UNSPECIFIED measure mode.

prepareChildren(); final Behavior b = lp.getBehavior(); if (b == null || ! b.onMeasureChild(this, child, childWidthMeasureSpec, keylineWidthUsed, childHeightMeasureSpec, 0)) { onMeasureChild(child, childWidthMeasureSpec, keylineWidthUsed, childHeightMeasureSpec, 0); }Copy the code

Combine LayoutParams with prepareChildren()

        R.styleable.CoordinatorLayout_Layout_layout_behavior);
if (mBehaviorResolved) {
    mBehavior = parseBehavior(context, attrs, a.getString(
            R.styleable.CoordinatorLayout_Layout_layout_behavior));
}
Copy the code

We can see that Behavior B is appBarLayout. layout_behavior set in the layout. We can see that Behavior/onMeasureChild has a layer of measurement, Behavior/onMeasureChild

@Override
public boolean onMeasureChild(
    @NonNull CoordinatorLayout parent,
    @NonNull T child,
    int parentWidthMeasureSpec,
    int widthUsed,
    int parentHeightMeasureSpec,
    int heightUsed) {
  final CoordinatorLayout.LayoutParams lp =
      (CoordinatorLayout.LayoutParams) child.getLayoutParams();
  if (lp.height == CoordinatorLayout.LayoutParams.WRAP_CONTENT) {
    // If the view is set to wrap on it's height, CoordinatorLayout by default will
    // cap the view at the CoL's height. Since the AppBarLayout can scroll, this isn't
    // what we actually want, so we measure it ourselves with an unspecified spec to
    // allow the child to be larger than it's parent
    parent.onMeasureChild(
        child,
        parentWidthMeasureSpec,
        widthUsed,
        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
        heightUsed);
    return true;
  }

  // Let the parent handle it as normal
  return super.onMeasureChild(
      parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
}
Copy the code

Problems found the key to the if (lp) height = = CoordinatorLayout. LayoutParams. WRAP_CONTENT), Caused the MeasureSpec. The use of UNSPECIFIED, and the model can cause Recycleview. LayoutManager loading all of the item, cause the failure of reuse; AppBarLayout gives a fixed value or match_parent, which solves the problem, but then our layout UI doesn’t match the layout of our UI, which also causes the blank page to display. So this use of recycleView nesting is illegal use, contradictory use!

To solve the problem

  • The same use of RecycleView, as a part of RecycleView item, but it will also cause sliding conflict problems, and then through NestedScrollingParent3 external interception method, to solve the inner and outer layer of sliding conflict, the problem is solved smoothly
override fun onInterceptTouchEvent(e: MotionEvent?) : Boolean { if (e!! .action == MotionEvent.ACTION_DOWN) { val childRecyclerView = findCurrentChildRecyclerView() // 1. DoNotInterceptTouchEvent = doNotInterceptTouch(e.lawy, childRecyclerView) // 2. StopFling this.stopFling() childRecyclerView? .stopFling() } return if (doNotInterceptTouchEvent) { false } else { super.onInterceptTouchEvent(e) } }Copy the code
  • According to the business scenario, also can use baserecyclerviewadapterhelper, a good Adapter framework,

AddHeaderView adds an itemView, and notifyItemInserted(Position) adds a ReceiveView item

@JvmOverloads fun addHeaderView(view: View, index: Int = -1, orientation: Int = LinearLayout.VERTICAL): Int { if (! this::mHeaderLayout.isInitialized) { mHeaderLayout = LinearLayout(view.context) mHeaderLayout.orientation = orientation mHeaderLayout.layoutParams = if (orientation == LinearLayout.VERTICAL) { RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT) } else { RecyclerView.LayoutParams(WRAP_CONTENT, MATCH_PARENT) } } val childCount = mHeaderLayout.childCount var mIndex = index if (index < 0 || index > childCount) { mIndex = childCount } mHeaderLayout.addView(view, mIndex) if (mHeaderLayout.childCount == 1) { val position = headerViewPosition if (position ! = -1) { notifyItemInserted(position) } } return mIndex }Copy the code