一、什么是RecyclerView
RecyclerView介绍
为有限的屏幕显示大量数据的灵活的View
ListView的局限
- 只有纵向列表一种布局
- 没有支持动画的Api,动画实现复杂
- 接口设计和系统不一致?
- setOnItemClickListener
- setOnItemLongClickListener
- setSelection()
- 没有强制实现ViewHolder
- 性能不如RecyclerView
RecyclerView的优势
-
默认支持Linear、Grid、StaggeredGrid三种布局,并每个布局支持横竖两个方向
并支持扩展布局类型
-
友好的ItemAnimator 动画Api
调用noticeItemXXX 就显示默认的动画
-
强制实现 ViewHolder
-
解耦的架构设计
每个类的职责分明 -
相比ListView有更好的性能
ViewHolder 究竟是什么
viewHolder是保存View引用的容器类
-
ViewHolder与ItemView一一对应
-
ViewHolder解决了重复FindViewById的问题
FindViewById有多耗性能?
-
ViewHolder和ItemView的复用没有关系
RecyclerView的缓存原理
-
listView缓存原理
-
RecyclerView缓存
显示区的View为Scrap,此类型的缓存会直接使用,刚移除的item放到Cache,一般上下各两个,这种类型的缓存也可以直接使用,不会调用onBindViewHolder,RecyclerViewPool里的缓存是脏了的,当复用时需要调用onBindViewHolder重新绑定数据
RecyclerView优化策略
-
setOnItemClickListener设置在onBindViewHolder会导致重复创建,可以写在onCreateViewHolder里
-
LinearLayoutManager.setInitialPrefetChildItemCount()?
当用户滑动到横向滑动的ItemRecyclerView的时候,由于创建更复杂的RecyclerView以及多个子View,可能会导致页面卡顿。
RenderThread的存在,RecyclerView会进行prefetch
LinearLayoutManager.setInitialPrefetchItemCount(横向列表初次显示时可见的item个数)
- 只有linearLayoutManager有这个Api
- 只有嵌套在内部的RecyclerView才会生效
-
RecyclerView.setHasFixedSize()
由于RecyclerView的内容改变会导致requestLayout请求View重绘,而setHasFixedSize则只会调用layoutChildren(),跳过view的measure流程,这样可以节省一部分性能,所以如果Adapter的数据变化不会导致RecyclerView的大小变化则设置这个方法可以优化性能
-
多个RecyclerView共享RecyclerViewPool
-
DiffUtil
适用于整个页面需要刷新,但是有部分数据可能相同的情况
new DiffUtil.Callback() { @Override public int getOldListSize() { //旧数据源大小 return 0; } @Override public int getNewListSize() { //新数据源大小 return 0; } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { //两个对象是否应该是同一个Item return false; } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { //两个对象的同一个Item是否内容改变了 return false; } @Nullable @Override public Object getChangePayload(int oldItemPosition, int newItemPosition) { //Item局部更新,只某个属性变了 return super.getChangePayload(oldItemPosition, newItemPosition); } };