前言
最近写一个项目使用了嵌套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加载。