RV和LV的区别
LV:
- 继承并重写BaseAdapter类,布局效果单一
- 自定义ViewHolder和convertView的复用优化
- 可以通过addHeaderView()和addFooterView()添加下拉刷新的头部view与上拉加载更多的底部view,且不会影响Adapter的编写
- 在刷新条目数据时通常使用notifyDataSetChanged()方法这种刷新数据是全局刷新的方式,每个item的数据都会重新加载一遍,会消耗更多的资源,如果要实现局部刷新,则需要在Adapter中自定义方法,调用getFirstVisiblePosition()获取到对应item的position,然后调用getView()方法来刷新这个item的数据
- 没有动画效果的实现,需要自己在Adapter中自己实现
- 有现成的点击方法->onItemClickListener()->onItemLongClickListener()-onItemSelectedListener()
- 没有嵌套滚动机制
RV:
- 继承重写RecyclerView.Adapter类,覆写onCreateViewHolder方法和onBindViewHolder方法,实现自己的ViewHolder类,继承重写RecyclerView.Holder,通过设置LayoutManager以及layout的布局效果:线性,表格,瀑布流或者自定义LayoutManager
- 复用优化有四级缓存,无需自定义,如果不满足于默认设置,可以手动设置pool等缓存优化
- 没有添加HeaderView和FooterView的方法,需要在Adapter中根据getItemViewType()自己实现,但是这样会导致实际position的值产生偏差
- RecyclerView可以使用全局刷新和局部刷新->notifyItemChanged(int position)
- 有已经封装好的简单动画->notifyItemChange(),notifyDataInserted(),notifyItemMoved等,如需自定义动画,需要实现动画接口RecyclerView.ItemAnimator类,然后调用RecyclerView.setItemAnimator()设置动画效果
- 没有现成的点击事件,需要自己手动实现
- 实现了嵌套滑动机制.Android的事件分发机制中,Touch事件在进行分发时,有父View向子View传递,一旦子View消费了此事件则父View不在接受后续的分发处理,处理交由子View进行;但是嵌套滚动机制通过实现NestedScrollingChild()和NestedScrollingParent()两个接口可以让子View和父View同时处理此Touch事件
RV的四级缓存
- Scrap:一级缓存,缓存了屏幕内显示的所有viewholder,在这一级缓存的viewholder可以有效的避免重复的create和bind,缓存的时机是onLayout,并且用完后立即清空;在列表滑出新的item时,LayoutManager会先把屏幕中的所有的viewholder废弃掉,放入mAttachedView中,然后再根据flag重新布局每个itemview,并清空ScrapView
- mAttachedScrap,ArrayList,用于存放当前屏幕中的viewholder;用于存放flag为失效,移除的viewholder和完全没有改变的viewholder,有多少存多少;从这里获得的viewholder不需要走onBindViewHolder()方法
- mChangedScrap,ArrayList,用于存放数据被更新后的viewholder,也就是flag为更新的viewholder;这些viewholder需要被adapter重新绑定
- mCachedViwe,默认大小为2,用于存放预读取的viewholder,只有当所需的viewholder和position相同并且flag为有效时才获取此viewhodler,由于已经判断了viewholder是有效的,所以就不需要进行bind操作了;由于mCacheedView是有大小限制的,因此,如果超过了默认缓存大小,则会移除mCachedViwe的第一个viewholder,然后把需要添加的viewholder添加进入mCachedViwe,被移除的和不能加入的viewholder则会加入到mRecyclerViewPool中
- ViewCacheExtension,自定义缓存,通常用不到
- RecyclerViewPool,缓存池,根据viewType来缓存viewHolder,每个viewType可缓存的数量为5,可以动态的改变
RV的flag种类:失效,废弃,分离,移除,绑定,更新
缓存流程
RV复用的流程就是获取viewholder的流程;获取viewholder从Recycler的getViewForPosition开始
- 在mAttachedScrap或者mChangedScrap中根据position和flag查找到对应viewholder,获取并返回viewholder,根据flag决定viewhodler是否重新绑定
- 如果上一步没有获取到viewhodler,则从mCacheViews中匹配position获取viewholder缓存,获取并返回viewholder
- 如果上一步没有获取到viewhodler,则从ViewCacheExtension中获取viewholder,获取并返回viewholder
- 如果上一步没有获取到viewhodler,则从RecyclerViewPool中根据itemtype获取缓存的viewhodler,清除获取的viewhodler的所有标记位置,确保viewhodler能重新被adapter绑定
- 如果上一步没有获取到viewhodler,则走adapter的CreateViewHolder方法,创建一个新的viewholder,并经过adapter的bindViewHolder绑定改viewholder
源码分析干货:
https://www.jianshu.com/p/c52b947fe064
https://www.jianshu.com/p/efe81969f69d
https://juejin.im/post/5b79a0b851882542b13d204b