By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account
RecyclerView 是什么?

RecyclerView 是Android5.0推出,Google工程师在support-v7包中引入的一个全新列表控件,用于显示庞大数据集容器,可通过保持有限数量的视图进行非常有效的滚动操作,它不关心item是否显示在正确的位置以及如何显示,通过LayoutManager控制布局是横向还是纵向,它不关心 item 如何 分隔,通过 ItemDecoration 来绘制分割线,它不关心 item 增加或删除的动画效果,你可以通过 ItemAnimation 绘制你想要的动画效果, RecyclerView 仅仅关注如何回收和复用view,如果有数据集合,其中元素将因用户操作或网络事件而发生改变,建议使用 RecyclerView

RecyclerView使用

一.添加依赖

使用RecyclerView需要在 app/build.gradle添加 相关依赖,然后同步一下就可以使用依赖了:

 implementation 'com.android.support:recyclerview-v7:25.3.1'

二.编写代码

创建布局文件

<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
   <androidx.recyclerview.widget.RecyclerView
           android:id="@+id/recyclerview"
           android:layout_width="match_parent"
           android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

创建完成后在Activity获取RecycleView对象,并声明 LayoutManager 与 Adapter,代码如下:

public class MainActivity extends AppCompatActivity implements SimpleAdapter.OnItemClickListener {
    private RecyclerView mRecyclerView;
    private List<String> mDatas;
    private SimpleAdapter mAmAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initDatas();
        initView();
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        final int itemId = item.getItemId();
        switch (itemId) {
            case R.id.action_add:
                mAmAdapter.addData(1);
                mRecyclerView.setAdapter(mAmAdapter);
                break;
            case R.id.action_delete:
                mAmAdapter.deleteData(1);
                mRecyclerView.setAdapter(mAmAdapter);
                break;
            case R.id.action_grid_view:
                mRecyclerView.setAdapter(new SimpleAdapter(this, mDatas, false));
                mRecyclerView.setLayoutManager(new GridLayoutManager(this, 5));
                break;
            case R.id.action_list_view:
                mRecyclerView.setAdapter(new SimpleAdapter(this, mDatas, true));
                mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
                break;
            case R.id.action_hor_grid_view:
                mRecyclerView.setAdapter(new SimpleAdapter(this, mDatas, false));
                mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.HORIZONTAL));
                break;
            case R.id.action_stagger_view:
                startActivity(new Intent(this, StaggeredGridViewActivity.class));
                break;
            default:
                break;
        return super.onOptionsItemSelected(item);
    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        mAmAdapter = new SimpleAdapter(this, mDatas, true);
        // 设置RecyclerView的布局管理
        mRecyclerView.setAdapter(mAmAdapter);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
        mAmAdapter.setOnItemClickListener(this);
    private void initDatas() {
        mDatas = new ArrayList<>();
        for (int i = 'A'; i < 'z'; i++) {
            mDatas.add("" + (char) i);
    @Override
    public void onItemClick(View view, int position) {
        Toast.makeText(MainActivity.this, "Click:" + position
                , Toast.LENGTH_LONG).show();
    @Override
    public void onItemLongClick(View view, int position) {
        mAmAdapter.deleteData(position);

  RecycleView 和 ListView 一样需要适配器的,但是 RecycleView 需要设置 布局管理器(setLayoutManager),这是为了方便扩展,这里使用了 LinearLayoutManager.其中 Adapter 的创建比较关键,来看一下 SimpleAdapter 的代码:

public class SimpleAdapter extends RecyclerView.Adapter<MyViewHolder> {
    public LayoutInflater mInflater;
    private Context mContext;
    private List<String> mDatas;
    private boolean mIsListView;
    public OnItemClickListener mListener;
    public interface OnItemClickListener {
        void onItemClick(View view, int position);
        void onItemLongClick(View view, int position);
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mListener = listener;
    public SimpleAdapter(Context context, List<String> datas, boolean isListView) {
        this.mContext = context;
        this.mDatas = datas;
        this.mInflater = LayoutInflater.from(context);
        this.mIsListView = isListView;
    public void addData(int position) {
        if (position >= 1) {
            mDatas.add(mDatas.get(position));
            notifyItemInserted(position);
    public void deleteData(int postion) {
        mDatas.remove(postion);
        notifyItemRemoved(postion);
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        final View view = mInflater.inflate(mIsListView ? R.layout.item_simple_list_view : R.layout.item_simple_text_view, parent, false);
        MyViewHolder viewHolder = new MyViewHolder(view);
        return viewHolder;
    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        holder.tv.setText(mDatas.get(position));
        setUpItemEvent(holder);
    public void setUpItemEvent(@NonNull final MyViewHolder holder) {
        if (mListener != null) {
            final int layoutPosition = holder.getLayoutPosition();
            holder.tv.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mListener.onItemClick(holder.tv, layoutPosition);
            holder.tv.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
                    mListener.onItemLongClick(holder.tv, layoutPosition);
                    return false;
    @Override
    public int getItemCount() {
        return mDatas.size();

  上面用到 item_simple_text_view.xml 布局文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:orientation="vertical"
             android:layout_width="wrap_content"
             android:background="@color/colorAccent"
             android:layout_margin="3dp"
             android:id="@+id/layout_frame"
             android:layout_height="wrap_content">
    <TextView
            android:id="@+id/id_tv"
            android:gravity="center"
            android:layout_width="72dp"
            android:layout_height="72dp"/>
</FrameLayout>

  SimpleAdapter 继承 RecyclerView.Adapter ,需要一个ViewHolder 泛型,创建 ViewHolder 需要继承 RecycleView.ViewHolder , ViewHolder 的构造方法需要传递 View 对象, View 对象 需要继承 RecycleView.ViewHolder,ViewHolder 构造方法需要传递 View对象,View对象会和 ViewHolder 进行绑定.

public class MyViewHolder extends RecyclerView.ViewHolder {
    TextView tv;
    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        tv = (TextView) itemView.findViewById(R.id.id_tv);
  可以发现  RecyclerView.Adapter  设计针对性很强,强制程序员通过ViewHolder 和 复用 View 进行优化,不会出现之前 ListView 不采取 优化情况.这种机制避免创建过多View和频繁调用findViewById的方法

写完这些代码后,这个simple就可以运行起来了,从例子也可以看出,RecycleView的用法并不比 ListView 复杂,反而更加灵活好用,它将数据,排列方式,数据展示方式都分割开来,因此自定义的形式也非常多,非常灵活

RecyclerView不同布局的排列方式

上面的效果是水平列表,还可以选择其他排列方式,非常灵活,这就是比单一的listView/GridView强大的地方

  • ListView
  • 以垂直列表方式展示显示项目

      mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
  • GrideView
  • 以垂直列表方式展示显示表格布局

      mRecyclerView.setLayoutManager(new GridLayoutManager(this, 5));
  • 横向 ListView
  • 如果想设置一个横向的列表,只要设置 LinearLayoutManager 就行,注意, 要声明 LayoutManager 的类型是 LinearLayoutManager ,而不是父类的 LayoutManager

     mRecyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
  • 横向 GrideView
  • 以水平列表方式展示显示表格布局

    mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(5, StaggeredGridLayoutManager.HORIZONTAL))```

    一.高度绘制

     for (int i = 0; i < mDatas.size(); i++) {
                mHeight.add((int) (100 + Math.random() * 300));
    

    二.布局绘制

       @Override
        public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
            final ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
            layoutParams.height = mHeight.get(position);
            holder.itemView.setLayoutParams(layoutParams);
            holder.tv.setText(mDatas.get(position));
    

    三.设置RecyclerView的布局管理

      StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
      mRecyclerView.setLayoutManager(manager);

    四.RecyclerView添加点击事件

      当使用一段时间的RecycleView,发现为其实现每一项点击事件并没有ListView那么轻松,ListView直接加一个 OnItemClickListerner 即可,实际上我们不要把
    RecyclerView 当作 ListView使用,希望大家把他看成一个容器,里面包含不同的item,它们可以设置不同方式的排列组合,非常灵活,点击事件按照自己的意愿进行实现.那么如何为RecycleView添加点击事件呢?
      其实我发现,Adapter是添加点击事件一个很好的地方,里面构造布局等View的主要场所,也是布局和数据进行绑定的地方,首先在 Adapter 中创建一个实现点击接口,其中View是点击 item,data是数据,postion是条目位置,因为我们想知道点击的区域部分的数据和位置是什么,以便下一步进行操作:

        public interface OnItemClickListener {
           void onItemClick(View view, int position);
           void onItemLongClick(View view, int position);
    

      定义完接口,在 Adapter 中添加 要实现的接口和添加设置的方法

     public OnItemClickListener mListener;
     public void setOnItemClickListener(OnItemClickListener listener) {
           this.mListener = listener;
    

      那么这个接口用在什么地方呢?如下代码,为Adapter 实现 onClickListerner 方法:

        @Override
      public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
          holder.tv.setText(mDatas.get(position));
          setUpItemEvent(holder);
      public void setUpItemEvent(@NonNull final MyViewHolder holder) {
          if (mListener != null) {
              final int layoutPosition = holder.getLayoutPosition();
              holder.tv.setOnClickListener(new View.OnClickListener() {
                  @Override
                  public void onClick(View view) {
                      mListener.onItemClick(holder.tv, layoutPosition);
              holder.tv.setOnLongClickListener(new View.OnLongClickListener() {
                  @Override
                  public boolean onLongClick(View view) {
                      mListener.onItemLongClick(holder.tv, layoutPosition);
                      return false;
    

    做完这些事情就可以在 Activity 或者其他地方 为 RecycleView 添加项目点击事件了,如:

     private void initView() {
          mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview);
          mAmAdapter = new SimpleAdapter(this, mDatas, true);
          // 设置RecyclerView的布局管理
          mRecyclerView.setAdapter(mAmAdapter);
          mRecyclerView.setLayoutManager(new LinearLayoutManager(this, RecyclerView.HORIZONTAL, false));
          mAmAdapter.setOnItemClickListener(this);
      @Override
      public void onItemClick(View view, int position) {
          Toast.makeText(MainActivity.this, "Click:" + position
                  , Toast.LENGTH_LONG).show();
      @Override
      public void onItemLongClick(View view, int position) {
          mAmAdapter.deleteData(position);
    

    五.RecycleView添加删除数据
    以前在ListView中,只要 修改数据后用 Adapter 的 notifyDatasetChange 一下就可以更新界面.然而,在RecycleView 中还有高级的用法,可以让添加或者删除条目自带动画,可以在SimpleAdapter 传创建 addItem 和 removeItem 方法.

    添加数据:

        public void addData(int position) {
           if (position >= 1) {
               mDatas.add(mDatas.get(position));
               notifyItemInserted(position);
    

    删除数据:

           public void deleteData(int postion) {
           mDatas.remove(postion);
           notifyItemRemoved(postion);
    

    注意,这里更新数据集不是 adapter.notifyDataSetChange(),而是 notifyItemInserted(postion)与 notifyItemRemoved(postion),否则没有动画效果

    RecyclerView核心类

    Adapter
      使用RecyleView之前需要继承 自 RecyleView.Adapter 的适配器,作用是将适配器与每一个 item 界面进行绑定

    ViewHolder

  • viewHolder 和 item view 是什么关系?一对一?一对多?还是多对一?
  • view Holder 解决的是什么问题?

    view Holder 的 Listview item view 复用有什么关系?

      没有实现 view Holder 的 getView() 会重复执行 findViewById,findViewById 底层实现是一个 dns ,深度优先复杂度,所以viewHolder模式实现了getView方法,他的来历是用来保存View的convertView

    不实现 view Holder 还会复用 item view 吗?这个问题我还有待研究.

    LayoutManager
      LayoutManager 用来确定 每一个 item 如何排列摆放,何时展示和隐藏.回收或重用一个View时,LayoutManager会向适配器请求的数据替换旧的数据,这种机制避免创建过多的View和频繁调用findViewById的方法

    ItemDecoration

    ItemAnimation

    RecyclerView与ListView相比的优势

      因为ListView只有纵向列表一种布局,不像RecyleView一样支持 Linear, Grild ,Stagged,Stagged ,Grid 各种可扩展布局,没有支持动画的API,但是RecyleView可以通过ItemAnimation自定义你想要的动画,相关监听接口如:setOnClickListerner(),setOnLongItenListerner(),setSelection()的设计和系统也不一致,并且没有强制实现ViewHolder,RecyleView做到了这一点,降低了耦合,另外ListView性能也不如RecyclerView,所以强烈推荐大家使用RecyclerView

    RecyclerView 滑动场景下的回收复用涉及到的结构体两个:
    mCachedViews 和 RecyclerViewPool

    mCachedViews 优先级高于 RecyclerViewPool,回收时,最新的 ViewHolder 都是往 mCachedViews 里放,如果它满了,那就移出一个扔到 ViewPool 里好空出位置来缓存最新的 ViewHolder。

    复用时,也是先到 mCachedViews 里找 ViewHolder,但需要各种匹配条件,概括一下就是只有原来位置的卡位可以复用存在 mCachedViews 里的 ViewHolder,如果 mCachedViews 里没有,那么才去 ViewPool 里找。

    在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type 一样,有找到,就可以拿出来复用,重新绑定下数据即可。

    如果不要求动画,可用通过 ((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(false); 把默认动画关闭来提高性能

    TextView 使用 String.toUpperCase 替换 android:textAllCaps="true"

    TextView 使用 StaticLayout 或者 DynamicLayout 来自定义view替换它

    重新 RecyclerView.onViewRecycled(holder) 回收资源

    RecycleView.setItemViewCacheSize(size) 加大 RecyclerView 缓存空间,利用空间换时间策阅来提高流程性

    如果多个 RecyclerView 的 adapter 是一样的,比如嵌套的 RecyclerView 存在一样的adapter,可以通过 RecyclerView.setRecycledViewPool(pool); 共有一个 RecycledViewPool

    对于 ItemView 设置监听器,不要对每一个 item 都调用 addXxListener,应该共有一个 XxListener 根据 id 来进行不同操作,优化了对象的频繁创建带来的资源消耗。

    通过 getExtraLayoutSpace 来增加 RecyclerView 预留的额外空间(显示范围内,应该额外缓存的空间) ,如下所示:

       new LinearLayoutManager(this) {
        @Override
        protected int getExtraLayoutSpace(RecyclerView.State state) {
            return size;
              

    recyclerView算是Android中比较常用的控件了,平常的使用也很简单,没什么说的。
    另外,recyclerView也经常会有嵌套使用和多条目布局的使用方法,嵌套使用时要注意处理是否有滑动冲突,多条目布局就是定义多个ViewHolder来区分不同的条目。

    另外使用itemDecoration可以灵活控制布局之间的间距和装饰等效果。

    缓存机制的话确实还没读过源码,找了篇技术文章,可以参考下:https://blog.csdn.net/wzy_1988/article/details/81569156

    RecyclerView vs ListView
    ListView相比RecyclerView,有一些优点:

    1.addHeaderView(), addFooterView()添加头视图和尾视图。
    2.通过”android:divider”设置自定义分割线。
    3.setOnItemClickListener()和setOnItemLongClickListener()设置点击事件和长按事件。

    这些功能在RecyclerView中都没有直接的接口,要自己实现(虽然实现起来很简单),因此如果只是实现简单的显示功能,ListView无疑更简单。

    RecyclerView相比ListView,有一些明显的优点:

    1.默认已经实现了View的复用,不需要类似if(convertView == null)的实现,而且回收机制更加完善。
    2.默认支持局部刷新。
    3.容易实现添加item、删除item的动画效果。
    4.容易实现拖拽、侧滑删除等功能。

    RecyclerView是一个插件式的实现,对各个功能进行解耦,从而扩展性比较好。

    找到一篇基本可以全面了解recyclerview的文章,可以参考下
    https://www.jianshu.com/p/4f9591291365

    RecyclerView vs ListView
    ListView相比RecyclerView,有一些优点:

    1.addHeaderView(), addFooterView()添加头视图和尾视图。
    2.通过”android:divider”设置自定义分割线。
    3.setOnItemClickListener()和setOnItemLongClickListener()设置点击事件和长按事件。

    这些功能在RecyclerView中都没有直接的接口,要自己实现(虽然实现起来很简单),因此如果只是实现简单的显示功能,ListView无疑更简单。

    RecyclerView相比ListView,有一些明显的优点:

    1.默认已经实现了View的复用,不需要类似if(convertView == null)的实现,而且回收机制更加完善。
    2.默认支持局部刷新。
    3.容易实现添加item、删除item的动画效果。
    4.容易实现拖拽、侧滑删除等功能。

    RecyclerView是一个插件式的实现,对各个功能进行解耦,从而扩展性比较好。

    找到一篇基本可以全面了解recyclerview的文章,可以参考下
    https://www.jianshu.com/p/4f9591291365

    那你是如何解决下划线渲染两次的呢?

  • 使用LinearLayoutManager.setInitialPrefetchItemCount(count)设置嵌套在内部的横向RecyclerView的初次显示Item个数
  • Item高度固定时(数据变化也不会导致Item高度变化),使用RecyclerView.setHasFixedSize(true)
  • 多个RecyclerView共用一个RecyclerViewPool
  • DiffUtil局部刷新
  • RecyclerView缓存

  • 第一层Scrap & 第二层Cache:缓存当前屏幕的ItemView。都是根据position去缓存和获取复用ItemView,复用时不需要再调用onBindViewHolder()重新进行数据绑定了。
  • 第三层ViewCacheExtension:开发者自定义的缓存策略
  • 第四层缓存池:存放已经滑出屏幕的View,需要复用时根据item type去查找是否有可复用的ItemView,如果有可复用的就拿出来再重新进行数据绑定,没有就调用onCreateViewHolder()再新建一个ItemView。
  • RecyclerView 核心要点

    RecycleView 是什么

    A flexible view for providing a limited window into a large data set
    有限的屏幕显示大量的数据的灵活的视图

    ListView 的局限

  • 只支持纵向列表的滑动
  • 没有支持动画的 API
  • 接口设计和系统设计不一致
  • setOnItemClickListener()
  • setOnItemLongClickListener()
  • setSelection()
  • 没有强制实现 ViewHolder
  • 没有实现ViewHolder 的 getView();
    每次都实现findViewById() DFS 浪费时间,消耗性能a/需要实现 ViewHolder 并且 ItemView.setTag(ViewHolder)
  • 性能不如 RecycleView
  • RecycleView 的优势

  • 默认支持 Linear,Grid,Staggered Grid 三种布局
  • 友好的 ItemAnimator 动画 API
  • 强制实现 ViewHolder
  • 解耦的架构设计
  • RecycleView
  • LayoutManager
  • ItemAnimator
  • Adapter
  • 两层缓存机制
    Active View:指屏幕能看到的 ItemView
    Android 刷新屏幕的时候会将屏幕中的 View 清空掉,再加进来,这时回收的使用的就是Active View,这时不需要重新绑定
    Scrap View:屏幕中看不到的 ItemView

    RecycleView 缓存原理

    RecycleView 缓存的是 ViewHolder ,使用了四层缓存机制

  • Scrap:屏幕内部的 ItemView,通过数据集的 Position 找到的,可以直接复用不需要绑定
  • Cache:移出屏幕的 ItemView 放入一个CacheView(默认个数为2),就是比屏幕多两个 ItemView, 方便来回翻少量的View,可以直接复用不需要绑定
  • ViewCacheExtension:用户自定义的缓存机制
  • **ViewCacheExtension Example **
    广告夹杂在 RecycleView 内,并且不会发生变化,广告和内容分开请求

  • 每页一共有四个广告
  • 短期内不会发生变化
  • Cache 只关心 position,不关心 view type
  • RecycleViewPool 只关心 view type,每次都要重新绑定
  • 解决方法:在 ViewCacheExtension 保存四个广告的 Card
  • RecycleViewPool:被废弃的 ItemView ,内部的 data 都是 dirty 的。通过ViewType来重新Bind数据的
  • 注意广告的 impression

  • ListView 通过 getView() 统计?准确!用户看到item的时候一定会通过 getView() 「即使发生了复用」
  • RecycleView 通过 onBindView() 统计?错误!发生复用的时候不通过 onBindView() Scrap,Cache 不回发生重新绑定!
  • RecycleView 通过 onViewAttachedToWindow() 统计!这时每当 ItemView 出现在用户视野里的时候都会回调。
  • 可能不知道的 RecyclerView 性能优化策略

  • 在 onBindViewHolder() 设置点击监听?
    在 onBindViewHolder() 里设置点击监听器会导致重复创建点击监听器,会造成内存抖动
    在 onCreateViewHolder()/ViewHolder Constructor 里设置点击监听,ItemView - ViewHolder - View.OnClickListener 三者一一对应
    也可以只设置一个 ViewOnClickListener ,坏处是处理逻辑都在一起,还会造成数据耦合严重(要取出点击View的对象)
  • LinearLayoutManager.setInitialPrefetchItemCount()
  • 内部嵌套中的 RecycleView ,用户滑动到横向滑动的item RecycleView 的时候,由于需要创建更复杂的 RecycleView 及多个子 View,可能会导致页面卡顿
  • 由于 RenderThread(分担主线程的渲染压力,放到这里来执行) 的存在,RecycleView 会进行 prefetch (API 21⬆️)
  • LinearLayoutManager.setInitialPrefetchItemCount(横向列表初始显示时可见的 item 个数)
  • 只有 LinearLayoutManager 有这个 API
  • 只有在嵌套在内部的RecycleView 才会生效
  • 多个 RecyclerView 共用一个 RecycleViewPool
    默认是每一个 RecyclerView 用自己的 RecycleViewPool,可以通过 API 设置共享缓存池

    RecyclerView.RecycledViewPool recycledViewPool = new RecyclerView.RecycledViewPool();
            mRecyclerView.setRecycledViewPool(recycledViewPool);
            mRecyclerView1.setRecycledViewPool(recycledViewPool);
            mRecyclerView2.setRecycledViewPool(recycledViewPool);
    

    getViewType

    DiffUtil

  • 局部更新方法 notifyItemXXX() 不适用于所有情况
  • notifyDataSetChange() 会导致整个布局重回,重新绑定所有 ViewHolder,而且会可能失去可能的动画效果
  • DiffUtil 适用于整个页面需要刷新,但是有部分数据可能相同的情况
  • 内部算法使用的动画规划算法
  •  private DiffUtil.Callback mDiffUtilCallBack = new DiffUtil.Callback() {
        //旧列表的长度
        @Override public int getOldListSize() {return 0;}
        //新列表的长度
        @Override public int getNewListSize() {return 0;}
        //列表项的ID是否变化了
        @Override public boolean areItemsTheSame(int i, int i1) {return false;}
        //列表项的内容是否变化了
        @Override public boolean areContentsTheSame(int i, int i1) {return false;}
        //列表项的哪些内容变化了
        @Nullable @Override public Object getChangePayload(int oldItemPosition, int newItemPosition) {
            return super.getChangePayload(oldItemPosition, newItemPosition);
    
  • 在数据量很大的时候异步计算diff
  • 使用 Thread/Handler 将 DiffResult 发送到主线程
  • 使用RxJava 将 calculateDiff 操作放到后台线程执行
  • 使用 Google 提供 AsyncListDiff(Executor)/ListAdapter
  • RecyclerView内部缓存机制是四级缓存:Scrap、Cache、ViewCacheExtension、RecycledViewPool,RecyclerView是通过LayoutManager里面的Recycler来管理缓存;
    1、Scrap:屏幕内部的ItemView,通过数据集的position来找到对应的Item,可以直接取过来用;
    2、Cache:刚移出屏幕的ItemView,放到Cache里,当Cache里的ItemView重新进入屏幕时,也是通
    过position来找到对应的Item,直接可以使用,不需要走bindViewHolder()。Cache和 Scrap 一样,都是可以直接通过position来找到对应的Item,不需要重新绑定;
    3、ViewCacheExtension:自定义缓存,如果有自定义,需要在这里面找,没有的话直接跳过;
    4、RecycledViewPool:所有被废弃的ItemView的Pool,该pool里面的Item都是dirty的,需要通过
    ViewType来找到数据,找到数据的话,需要重新绑定,不走createViewHodler(),走bindViewHolder()。

    据我观察,公用一个 RecycledViewPool,不能达到完美的优化效果,只是节省了内存.
    RecyclerView.RecycledViewPool recycledViewPool = new RecyclerView.RecycledViewPool();

    mRecycledViewPool.setMaxRecycledViews(1, 10);
    mRecycledViewPool.setMaxRecycledViews(2, 10);
    mRecycledViewPool.setMaxRecycledViews(3, 10);
    mRecycledViewPool.setMaxRecycledViews(4, 10);
    mRecycledViewPool.setMaxRecycledViews(5, 10);

    mRecyclerView1.setRecycledViewPool(recycledViewPool);
    mRecyclerView2.setRecycledViewPool(recycledViewPool);
    mRecyclerView3.setRecycledViewPool(recycledViewPool);

    比如 mRecyclerView1 type=1,保存了 5个.
    在 mRecyclerView2 传入 recycledViewPool,并没有 mRecyclerView1 type=1的5个缓存.
    所以,当 mRecyclerView2 第一次 type=1 出来的时候,还是会执行 onCreateViewHolder,onBindViewHolder... ... ????