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

  1. getChangedScrapViewForPosition -- mChangeScrap 与动画相关
  2. getScrapOrHiddenOrCachedHolderForPosition -- mAttachedScrap 、mCachedViews
  3. getScrapOrCachedViewForId -- mAttachedScrap 、mCachedViews (ViewType,itemid)
  4. mViewCacheExtension.getViewForPositionAndType -- 自定义缓存 -- (使用情况:局部刷新??)
  5. 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 的缓存

  1. ViewHodler改变 不会进来 -- 先判断mCachedViews的大小
  2.  mCachedViews.size 大于默认大小 --- recycleCachedViewAt --- >addViewHolderToRecycledViewPool --- 缓存池里面的数据都是从mCachedViews里面出来的
  3.  2.addViewHolderToRecycledViewPool --> getRecycledViewPool().putRecycledView(holder);
  4. 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共用 同一个