RecyclerView相关属性
禁用滑动事件 : android:nestedScrollingEnabled="false"
设置滑动到边缘时无效果模式: android:overScrollMode="never"
设置不显示滚动条: android:scrollbars="none"
四级缓存
1. mChangeScrap与 mAttachedScrap :用来缓存还在屏幕内的 ViewHolder
2. mCachedViews :用来缓存移除屏幕之外的 ViewHolder
3. mViewCacheExtension :开发给用户的自定义扩展缓存,需要用户自己管理 View的创建和缓存
4. RecycledViewPool :ViewHolder 缓存池
复用:从集合中去获取
入口:滑动 Move 事件 --> scrollByInternal --> scrollStep --> mLayout.scrollVerticallyBy --> scrollBy --> fill --> layoutChunk --> layoutState.next --> addView(view);
layoutState.next --> getViewForPosition --> tryGetViewHolderForPositionByDeadline -->
怎么从集合中去获取:tryGetViewHolderForPositionByDeadline,分几种情况去获取ViewHolder
- getChangedScrapViewForPosition -- mChangeScrap 与动画相关
- getScrapOrHiddenOrCachedHolderForPosition -- mAttachedScrap 、mCachedViews
- getScrapOrCachedViewForId -- mAttachedScrap 、mCachedViews (ViewType,itemid)
- mViewCacheExtension.getViewForPositionAndType -- 自定义缓存 -- (使用情况:局部刷新??)
- getRecycledViewPool().getRecycledView -- 从缓冲池里面获取
RecycledViewPool -- 缓存池
ViewHolder -- 包装View的 --- ItemView
当没有缓存的时候??--- mAdapter.createViewHolder --》 onCreateViewHolder
多级缓存的目的 -- 为了性能
创建ViewHolder 后 绑定: tryBindViewHolderByDeadline--》 mAdapter.bindViewHolder--》onBindViewHolder
回收(缓存)机制:看这一个情况--- ViewHolder
LinearLayoutManager.onLayoutChildren --> detachAndScrapAttachedViews --> scrapOrRecycleView
--> 1.recycler.recycleViewHolderInternal(viewHolder); -- 处理 CacheView 、RecyclerViewPool 的缓存
- ViewHodler改变 不会进来 -- 先判断mCachedViews的大小
- mCachedViews.size 大于默认大小 --- recycleCachedViewAt --- >addViewHolderToRecycledViewPool --- 缓存池里面的数据都是从mCachedViews里面出来的
- 2.addViewHolderToRecycledViewPool --> getRecycledViewPool().putRecycledView(holder);
- scrap.resetInternal(); ViewHolder 清空
--> 2.recycler.scrapView(view);
缓存池 里面保存 只是 ViewHolder 类型 没有数据
public static class RecycledViewPool {
........
@Nullable
public ViewHolder getRecycledView(int viewType) {
final ScrapData scrapData = mScrap.get(viewType);
if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
for (int i = scrapHeap.size() - 1; i >= 0; i--) {
if (!scrapHeap.get(i).isAttachedToTransitionOverlay()) {
return scrapHeap.remove(i);
}
}
}
return null;
}
}
去查找缓存和复用的一种情况
入口:复用:RecyclerView.onLayout --> dispatchLayout --》 dispatchLayoutStep2 --》 onLayoutChildren --》 fill
缓存:fill -->recycleByLayoutState-->recycleViewsFromStart --> recycleChildren --> removeAndRecycleViewAt --> recycler.recycleView --> recycler.recycleViewHolderInternal(viewHolder); -- 处理 CacheView 、RecyclerViewPool 的缓存
RecyclerView与ListView的对比
RecyclerView和ListView都是用于加载大量数据的控件,RecyclerView作为listview的改进加强型,相对于ListView,RecyclerView做出了以下布局效果、局部刷新、动画效果、缓存知识优化:
1.布局效果
ListView 的布局比较单一,只有一个纵向效果;
RecyclerView 的布局效果丰富, 可以在 LayoutMananger 中设置:线性布局(纵向,横向),表格布局,瀑布流布局在RecyclerView 中,如果存在的 LayoutManager 不能满足需求,可以自定义
LayoutManager
2.item点击事件
RecyclerView 不支持 item 点击事件,只能用回调接口来设置点击事件
ListView 的 item 点击事件直接是 setOnItemClickListener
3.局部刷新
在 ListView 中通常刷新数据是用 notifyDataSetChanged() ,但是这种刷新数据是全局刷新的(每个 item的数据都会重新加载一遍),这样一来就会非常消耗资源;
RecyclerView 中可以实现局部刷新,例如: notifyItemChanged() ;
如果要在 ListView 实现局部刷新,依然是可以实现的,当一个 item 数据刷新时在 Adapter中,实现一个notifyItemChanged() 方法,在方法里面通过这个 item 的 position ,刷新这个 item 的数据
4.动画效果
在 RecyclerView 中,已经封装好 API 来实现自己的动画效果;并且如果我们需要实现自己的动画效果,我们可以通过相应的接口实现自定义的动画效果(RecyclerView.ItemAnimator 类),然后调用RecyclerView.setItemAnimator() (默认的有 SimpleItemAnimator 与 DefaultItemAnimator );
但是ListView 并没有实现动画效果,但我们可以在 Adapter 自己实现 item 的动画效果;
5.缓存区别
层级不同
ListView 有两级缓存,在屏幕与非屏幕内。 mActiveViews + mScrapViews
RecyclerView 比 ListView 多两级缓存:支持开发者自定义缓存处理逻辑, RecyclerViewPool( 缓存池 ) 。并且支持多个离屏ItemView 缓存(缓存屏幕外 2 个 itemView )。
mAttachedScrap +mCacheViews +mViewCacheExtension + mRecyclerPool
缓存内容不同
ListView 缓存 View 。
RecyclerView 缓存 RecyclerView.ViewHolder
RV优势
a.mCacheViews 的使用,可以做到屏幕外的列表项 ItemView 进入屏幕内时也无须 bindView 快速重用;
b.mRecyclerPool 可以供多个 RecyclerView 共同使用,在特定场景下,如 viewpaper+ 多个列表页下有优势.
总结缓存区别
1 ,封装了 viewholder , Listview 需要自己写 ViewHolder 缓存,而 RecyclerView 已经帮我们实现了。
2 , RecyclerView 的缓存机制有了加强, ListView 是 2 级缓存,而 RecyclerView 实现了 4 级缓存。
3 , RecyclerView 相对于 ListView 最大的加强是实现了局部刷新,这对于 ListView 需要刷新全部列表进步很多,特别适用于那些数据源经常发生改变的情况。
ListView( 两级缓存 ) :
是否需要回调createView | 是否需要回调bindView | 生命周期 | 备注 | |
mActiveViews | 否 | 否 | onLayout函数周期内 | 用于屏幕 itemView快 速重用 |
mScrapViews | 否 | 是 | 与mAdapter一致,当mAdatper被 更换时,mScrapViews即被清空 |
RecyclerView( 四级缓存 ) :
是否需要回调createView | 是否需要回调bindView | 生命周期 | 备注 | |
mAttachedScrap | 否 | 否 | onLayout函数周期内 | 用于屏幕内itemview快速重用 |
mCacheViews | 否 | 否 | 与mAdapter一致,当mAdapter被更换 时,mCacheViews即被缓存至 mRecyclerPool | 默认上限为2,即缓存屏幕外2 个itemView |
mViewCacheExtension | 不直接使用,需要用户在定制,默认不实现 | |||
mRecyclerPool | 否 | 是 | 与自身生命周期一致,不再被引用是即 被释放 | 默认上限为5,技术上可以实 现所有RecyclerViewPool共用 同一个 |