前言

最近写一个项目使用了嵌套RecycleView,但是加载完后,第一次滑动卡顿。找遍了所有的优化方案,很多方案只说了可以怎样怎样设置来进行优化,却没说什么场景下使用。特此总结汇总如下。先说我自己遇到的问题:

getExtraLayoutSpace

使用场景:一个itemView就占了一屏大小的RecycleView

我是最外面一个竖排的RecycleView,然后内部的第二个item用了GridLayoutManager布局的RecycleView ,但是外部的第一个item已经占满了第一屏,加载完后,滑动至第二个item,也就是子RecycleView的时候,就会卡顿一下,查看trace文件看是滑动后才开始子RecycleView的inflate等等操作。也就是这个时候导致了卡顿。

原因是RecyclerView初始加载时只加载一屏的元素并保存在内存中,滚动再复用,而我们的第二个item与第一个item不是同一个type,所以不能复用。

使用方法:

对外部RecycleView的LinearLayoutManager重写getExtraLayoutSpace方法。返回一个略大一些的值(单位是像素)。
源码中对其的解释是:这个方法设置了LayoutManager应该额外布局的空间。就是除了显示之外的空间大小。

LinearLayoutManager lyManager = new LinearLayoutManager(this){
            @Override
            protected int getExtraLayoutSpace(RecyclerView.State state) {
                return 360;
            }
        };
        rvShake.setLayoutManager(lyManager);

这个单位是像素,不要写的太小,我认为大小一个屏幕就可以了,或者更小一些,好像是一样的效果,大概是超过之后自动加载一个item。

setInitialPrefetchItemCount

使用场景:嵌套下的子RecycleView

默认嵌套下的子RecycleView只会预加载2个item,当你子RecycleView始终显示有四个(未对齐则是五个)时,使用这个方法设置为4个预加载item。原文注释如下:

* <p>For example, take a vertically scrolling RecyclerView with horizontally scrolling inner
     * RecyclerViews. The rows always have 4 items visible in them (or 5 if not aligned). Passing
     * <code>4</code> to this method for each inner RecyclerView's LinearLayoutManager will enable
     * RecyclerView's prefetching feature to do create/bind work for 4 views within a row early,
     * before it is scrolled on screen, instead of just the default 2.</p>
使用方法:

layoutManager.setInitialPrefetchItemCount(12);

android:focusableInTouchMode=“true”

子RecycleView在加载后,会自动获取到焦点,导致稍微滑动了一点,自动把子VIew拖过去显示。

对外部RecycleView的headVIew设置android:focusableInTouchMode=“true”;

使用notidyItemchange等代替notifydatasetchange

除非必须全局刷新的情况,否则尽可能的对item进行刷新。

图片一定要异步加载

Glide或者自己用Rxjava写异步,子线程获取到drawable,然后主线程再去set

共享对象池

嵌套,多个子RecycleView都是相同的adapter时:
共用一个对象池:

代码大意如下:
RecyclerView childView1 = new RecyclerView(context);
RecycledViewPool mSharedPool= view1.getRecycledViewPool();
RecyclerView view2 = new RecyclerView(context);
view2.setRecycledViewPool(mSharedPool);
RecyclerView view3 = new RecyclerView(context);
view3 .setRecycledViewPool(mSharedPool);

数据处理和视图加载区分开

onCreateViewHolder onBindViewHolder 只负责视图的加载,理论上直接从bean里get数据,一定不要做耗时的操作,比如 Html.fromHtml,比如数据的处理排序等等。

减少布局层数

如果使用RelativeLayout代替LinearLayout可以减少布局层数时,使用RelativeLayout,否则使用LinearLayout;

RecyclerView.setHasFixedSize(true);

Item 高度是固定并且需要additem,deleteitem时才会调用。如果你根本不添加删除item,不需要。

RecyclerView.addOnScrollListener(listener);

具体操作是在滑动中停止图片的加载,可以百度详细的做法。

RecycleView.setItemViewCacheSize(size);

设置缓存的个数,这里的ItemView其实是和数据已经绑定的,只有同一个item再次出现,才会从这里取到itemview加载。