美文网首页
RecyclerView与ListView对比

RecyclerView与ListView对比

作者: BKQ_SYC | 来源:发表于2019-01-23 17:52 被阅读5次

    RecyclerView继承自ViewGroup,RecyclerView是support-v7版本中新增的一个Widget,官方对它的介绍是:RecyclerView是ListView的升级版本,更加先进灵活,以下从几个方面对比RecyclerView和ListView。

    • 功能

      ListView布局比较单一,只有一个纵向效果。RecyclerView的布局效果丰富,通过设置不同的LayoutManager可实现横纵向效果,表格效果,瀑布流效果。

    • 空数据处理

      ListView中有个setEmptyView用来处理数据为空的情况,而RecyclerView需要根据数据判断处理空数据情况

    • 头尾布局

      ListView自带addHeaderView和addFooterView来添加头部底部item来实现,并不影响Adapter的编写
      RecyclerView需要借助Adapter实现头尾布局,通过设置ViewHolder不同的类型实现

    • 局部刷新

      ListView刷新数据用notifyDataSetChanged刷新所有数据,而RecyclerView可以调用notifyItemChanged实现局部刷新。当然,两者都可以通过position找到对应item的布局,然后刷新对应子布局,从而实现局部刷新

    • 动画效果

      RecyclerView自带动画效果,如果需要自定义动画可通过自定义RecyclerView.ItemAnimator类,然后调用setItemAnimator设置。ListView没有动画效果的实现,但可以对单个item添加动画实现动画效果,相对比较麻烦

    • item点击事件

      ListView自带onItemClickListener等方法
      RecyclerView提供addOnItemTouchListener监听item的触摸事件,通过addOnItemTouchListener加上Gesture Detector来实现item响应方法

    • 缓存机制

      ListView与RecyclerView缓存机制原理大致相似,滑动过程中,离开屏幕的ItemView即被回收纸缓存,进入屏幕的ItemView则会优先从缓存中获取

      • 缓存机制对比
      1. 缓存层级不同
        RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool,ListView和RecyclerView缓存机制基本一致

      1、mActiveViews和mAttachedScrap功能相似,意义在于快速重用屏幕上可见的列表项ItemView,而不需要重新createView和bindView
      2、mScrapView和mCachedViews + mRecyclerViewPool功能相似,意义在于缓存离开屏幕的ItemView,目的是让即将进入屏幕的ItemView重用
      3、RecyclerView的优势在于:

      a. mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无需bindView快速复用
      b. mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpager+多个列表页下有优势

      1. 缓存层级不同
      > 1、RecyclerView缓存RecyclerView.ViewHolder,抽象可理解为:View + ViewHolder(避免每次createView时调用findViewById) + flag(标识状态)
      > 2、ListView缓存View
      
      1. 获取缓存流程不同


        ListView获取缓存流程图.png
    RecyclerView获取缓存流程图.png
    1. RecyclerView中mCacheViews(屏幕外)获取缓存时,是通过匹配pos获取目标位置的缓存,这样做的好处是,当数据源数据不变的情况下,无需重新bindView。而同样是离屏缓存,ListView从mScrapViews根据pos获取相应的缓存,但是并没有直接使用,而是重新getView(即必定会重新bindView)
      final View scrapView = mRecycler.getScrapView(position);
      final View child = mAdapter.getView(position, scrapView, this)
      if (scrapView != null) {
           if (child != scrapView) {
               mRecycler.addScrapView(scrapView, position)
           } else {
               ········
           }
      }
    
    1. ListView中通过pos获取的是view,即pos->view;RecyclerView中通过pos获取的是viewholder,即pos -> (view,viewHolder,flag);从流程图中可以看出,标志flag的作用是判断view是否需要重新bindView,这也是RecyclerView实现局部刷新的一个核心

    ListView两级缓存,屏幕内、屏幕外

    ListView 是否回调createView 是否回调bindView 生命周期 备注
    mActiveView onLayout函数周期内 用于屏幕内ItemView快速重用
    mScrapViews 与mAdapter一致,当mAdapter被更换时,mScrapViews即被清空

    RecyclerView四级缓存,屏幕内、屏幕外、自定义缓存、缓存池

    RecyclerView 是否回调createView 是否回调bindView 生命周期 备注
    mAttachedScrap onLayout函数周期内 用于屏幕内ItemView快速重用
    mCacheViews 与mAdapter一致,当mAdapter被更换时,mCacheViews即被缓存至mRecyclerPool 默认上限为2,即缓存屏幕外2个ItemView
    mViewCacheExtension 不直接使用,需要用户再定制,默认不实现
    mRecyclerPool 与自身生命周期一致,不再被引用时即被释放 默认上限为5,技术上可以实现所有RecyclerView共用一个pool,前提它们的Adapter为同一个
    • 局部刷新

      RecyclerView更大的两点在于提供了局部刷新的接口,通过局部刷新,就能避免调用许多无用的bindView

      • RecyclerView局部刷新实现

        以notifyItemRemoved(1)为例,最终会调用requestLayout(),是整个RecyclerView重新绘制,过程为:
        onMeasure -> onLayout -> onDraw
        其中onLayout为重点,分为三步:

        1. 记录RecyclerView刷新前列表项ItemView的各种信息,如Top,Left,Bottom,Right用于动画的相关计算
        2. 真正测量布局大小,位置,核心函数为layoutChildren
        3. 计算不拒签后各个ItemView的状态,如Remove,Add,Move,Update等,如有必要执行相应的动画

        当调用notifyItemRemoved时,会对屏幕内ItemView做预处理,修改ItemView相应的pos以及flag。当调用fill()中RecyclerView.getViewForPosition(pos)时,RecyclerView通过对pos和flag的预处理,是的bindView只调用一次。ListView和RecyclerView最大的区别在于数据源改变时的缓存的处理逻辑。ListView是将所有的mActiveViews都移入到二级缓存mScrapViews,而RecyclerView则是更加灵活的对每个View修改标志位,区分是否bindView。

      RecyclerView局部刷新流程图.png

    相关文章

      网友评论

          本文标题:RecyclerView与ListView对比

          本文链接:https://www.haomeiwen.com/subject/khkjjqtx.html