美文网首页
解决scrollView嵌套RecyclerView导致Recy

解决scrollView嵌套RecyclerView导致Recy

作者: T_Y_H | 来源:发表于2020-09-22 11:21 被阅读0次

    现状

    • 在嵌套使用时,如果RecyclerView的adapter有1000条数据,则RecyclerView会创建1000个ViewHolder,每个ViewHolder会持有一个itemView。ViewHolder和itemView的快速大量创建容易anr

    问题分析

    • 最终发现LinearLayoutManager中的fill方法会导致adapter中的onCreateViewHolder方法调用,
    int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
           ....
           // 这个地方为true会导致adapter的onCreateViewHolder调用,正常情况下layoutState.mInfinite为false,影响recycleView子childView数量的是
            // remainingSpace > 0和layoutState.hasMore(state)
           while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
              .....
           }       
       }
    
    • 如上代码所示 while循环的条件有三个,正常的使用recycleView(不用scrollview嵌套reycleView),layoutState.mInfinite为false,嵌套的时候layoutState.mInfinite为true,我们看看ayoutState.mInfinite的解释


      image2020-9-22_10-5-9.png
    • 从注释来看,mInfinite在它为true时,LinearLayoutManager是不会限制recycleView的childView的个数,从而导致recycleview复用失效
    • 再看看mInfinite的赋值 image2020-9-22_10-7-50.png
    • 继续跟踪看看OrientationHelper的实现
      public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) {
            return new OrientationHelper(layoutManager) {
                .......
                @Override
                public int getEnd() {
                    return mLayoutManager.getHeight();
                }
    
                @Override
                public int getMode() {
                    return mLayoutManager.getHeightMode();
                }
                ......
               
            };
        }
    
    • 可以看到OrientationHelper的getEnd()和getMode()最后都是受mLayoutManager的HeightSepc(里面是height的size和heightMode)影响

    解决方案

    • 自定义view,并继承RecyclerView,重写onMeasure方法,对heightSpec进行判断,如果是是 MeasureSpec.UNSPECIFIED模式,改为MeasureSpec.AT_MOST
    public class CustomRecyclerView extends RecyclerView {
    
    
        public CustomRecyclerView(@NonNull Context context) {
            super(context);
        }
    
        public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void onMeasure(int widthSpec, int heightSpec) {
            //MeasureSpec.UNSPECIFIED 模式会导致LinearLayoutManager中的fill方法中判断是否可以无限制填冲整个recycleview为true,从而导致RecyclerView的复用失效
            if (MeasureSpec.getMode(heightSpec) == MeasureSpec.UNSPECIFIED) {
                int size = MeasureSpec.getSize(heightSpec);
                heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
            }
            super.onMeasure(widthSpec, heightSpec);
        }
    }
    

    相关文章

      网友评论

          本文标题:解决scrollView嵌套RecyclerView导致Recy

          本文链接:https://www.haomeiwen.com/subject/eqfwyktx.html