1、recyclerView.setHasFixedSize(true);
当Item的高度如是固定的,设置这个属性为true可以提高性能,尤其是当RecyclerView有条目插入、删除时性能提升更明显。RecyclerView在条目数量改变,会重新测量、布局各个item,如果设置了setHasFixedSize(true),由于item的宽高都是固定的,adapter的内容改变时,RecyclerView不会整个布局都重绘。具体可用以下伪代码表示:
void onItemsInsertedOrRemoved() {
if (hasFixedSize) layoutChildren();
else requestLayout();
}
2、使用getExtraLayoutSpace为LayoutManager设置更多的预留空间
在RecyclerView的元素比较高,一屏只能显示一个元素的时候,第一次滑动到第二个元素会卡顿。
如何解决这个问题呢,其实只需重写getExtraLayoutSpace()方法。根据官方文档的描述 getExtraLayoutSpace将返回LayoutManager应该预留的额外空间(显示范围之外,应该额外缓存的空间)。
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
@Override
protected int getExtraLayoutSpace(RecyclerView.State state) {
return 300;
}
};
4、避免创建过多对象
onCreateViewHolder 和 onBindViewHolder 对时间都比较敏感,尽量避免繁琐的操作和循环创建对象。例如创建 OnClickListener,可以全局创建一个。同时onBindViewHolder调用次数会多于onCreateViewHolder的次数,如从RecyclerViewPool缓存池中取到的View都需要重新bindView,所以我们可以把监听放到CreateView中进行。
优化前:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do something
}
});
}
优化后:
private class XXXHolder extends RecyclerView.ViewHolder {
private EditText mEt;
EditHolder(View itemView) {
super(itemView);
mEt = (EditText) itemView;
mEt.setOnClickListener(mOnClickListener);
}
}
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
//do something
}
}
5、局部刷新
可以用一下一些方法,替代notifyDataSetChanged,达到局部刷新的目的。notifyDataSetChanged会触发所有item的detached回调再触发onAttached回调。
notifyItemChanged(int position)
notifyItemInserted(int position)
notifyItemRemoved(int position)
notifyItemMoved(int fromPosition, int toPosition)
notifyItemRangeChanged(int positionStart, int itemCount)
notifyItemRangeInserted(int positionStart, int itemCount)
notifyItemRangeRemoved(int positionStart, int itemCount)
如果必须用 notifyDataSetChanged(),那么最好设置 mAdapter.setHasStableIds(true)
DiffUtil是support包下新增的一个工具类,用来判断新数据和旧数据的差别,从而进行局部刷新。
DiffUtil的使用,在原来调用mAdapter.notifyDataSetChanged()的地方:
// mAdapter.notifyDataSetChanged()
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(oldDatas, newDatas), true);
diffResult.dispatchUpdatesTo(mAdapter);
DiffUtil最终是调用Adapter的下面几个方法来进行局部刷新:
mAdapter.notifyItemRangeInserted(position, count);
mAdapter.notifyItemRangeRemoved(position, count);
mAdapter.notifyItemMoved(fromPosition, toPosition);
mAdapter.notifyItemRangeChanged(position, count, payload);
6、重写onScroll事件
对于大量图片的RecyclerView,滑动暂停后再加载;RecyclerView中存在几种绘制复杂,占用内存高的楼层类型,但是用户只是快速滑动到底部,并没有必要绘制计算这几种复杂类型,所以也可以考虑对滑动速度,滑动状态进行判断,满足条件后再加载这几种复杂的。
7、RecyclerView缓存
7.1 setItemViewCacheSize(int )
RecyclerView可以设置自己所需要的ViewHolder缓存数量,默认大小是2。cacheViews中的缓存只能position相同才可得用,且不会重新bindView,CacheViews满了后移除到RecyclerPool中,并重置ViewHolder,如果对于可能来回滑动的RecyclerView,把CacheViews的缓存数量设置大一些,可以减少bindView的时间,加快布局显示。
注:此方法是拿空间换时间,要充分考虑应用内存问题,根据应用实际使用情况设置大小。
网上大部分设置CacheView大小时都会带上:
setDrawingCacheEnabled(true)和setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH)
setDrawingCacheEnabled这个是View本身的方法,意途是开启缓存。通过setDrawingCacheEnabled把cache打开,再调用getDrawingCache就可以获得view的cache图片,如果cache没有建立,系统会自动调用buildDrawingCache方法来生成cache。一般截图会用到,这里的设置drawingcache,可能是在重绘时不需要重新计算bitmap的宽高等,能加快dispatchDraw的速度,但开启drawingcache,肯定也会耗应用的内存,所以也慎用。
7.2 复用RecycledViewPool
在TabLayout+ViewPager+RecyclerView的场景中,当多个RecyclerView有相同的item布局结构时,多个RecyclerView共用一个RecycledViewPool可以避免创建ViewHolder的开销,避免GC。RecycledViewPool对象可通过RecyclerView对象获取,也可以自己实现。
RecycledViewPool mPool = mRecyclerView1.getRecycledViewPool();
下一个RecyclerView可直接进行setRecycledViewPool
mRecyclerView2.setRecycledViewPool(mPool);
mRecyclerView3.setRecycledViewPool(mPool);
网友评论