Android RecyclerView 优化处理

01.RecyclerView滑动卡顿

  • RecyclerView滑动卡顿的原因有哪些?
    • 第一种:嵌套布局滑动冲突
      • 导致嵌套滑动难处理的关键原因在于当子控件消费了事件, 那么父控件就不会再有机会处理这个事件了, 所以一旦内部的滑动控件消费了滑动操作, 外部的滑动控件就再也没机会响应这个滑动操作了
    • 第二种:嵌套布局层次太深,比如六七层等
      • 测量,绘制布局可能会导致滑动卡顿
    • 第三种:比如用RecyclerView实现画廊,加载比较大的图片,如果快速滑动,则可能会出现卡顿,主要是加载图片需要时间
    • 第四种:在onCreateViewHolder或者在onBindViewHolder中做了耗时的操作导致卡顿。按stackoverflow上面比较通俗的解释:RecyclerView.Adapter里面的onCreateViewHolder()方法和onBindViewHolder()方法对时间都非常敏感。类似I/O读写,Bitmap解码一类的耗时操作,最好不要在它们里面进行。

04.瀑布流图片错乱问题解决

05.item点击事件放在哪里优化

  • 关于rv设置item条目点击事件有两种方式:1.在onCreateViewHolder中写;2.在onBindViewHolder中写;3.在ViewHolder中写。那么究竟是哪一种好呢?

    • 1.在onCreateViewHolder中写

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @NonNull
      @Override
      public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
      final View view = LayoutInflater.from(mContext).inflate(R.layout.item_me_gv_grid, parent, false);
      final MyViewHolder holder = new MyViewHolder(view);
      view.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
      if (listener != null) {
      listener.onItemClick(view, holder.getLayoutPosition());
      }
      }
      });
      return holder;
      }
    • 2.在onBindViewHolder中写

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      @Override
      public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
      holder.itemView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
      if (listener != null) {
      listener.onItemClick(holder.itemView, holder.getAdapterPosition());
      }
      }
      });
      }
    • 3.在ViewHolder中写

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      class MyViewHolder extends RecyclerView.ViewHolder {
      MyViewHolder(final View itemView) {
      super(itemView);
      itemView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
      if (listener != null) {
      listener.onItemClick(itemView, getAdapterPosition());
      }
      }
      });
      }
      }
  • onBindViewHolder() 中频繁创建新的 onClickListener 实例没有必要,建议实际开发中应该在 onCreateViewHolder() 中每次为新建的 View 设置一次就行。

08.拖拽排序与滑动删除优化

  • 拖拽效果优化
    • 在item被拖拽或侧滑时修改背景色,当动作结束后将背景色恢复回来,而ItemTouchHelper.Callback中正好有对应这两个状态的方法,分别是:onSelectedChanged()、clearView()。那么优化处理其实可以放到这两个方法中处理。
    • 左右滑动使item透明度变浅且缩小该如何实现呢?让item执行了两种属性动画而已,在ItemTouchHelper.Callback中有一个方法可以拿到item被拖拽或滑动时的位移变化,那就是onChildDraw()方法,在该方法中设置item渐变和缩放属性动画。
    • 出现问题,按照上面做法会出现删除后有空白item留出来,那么为什么会出现这种情况呢?并不是多出了两条空白数据,它们是正常的数据,只是看不到了,这是因为RecyclerView条目(itemView)覆用导致的,前面在onChildDraw()方法中对itemView设置了透明和缩小,而一个列表中固定只有几个itemView而已,当那两个透明缩小的itemView被再次使用时,之前设置的透明度和高度比例已经是0,所以就出现了这种情况,解决方法也很简单,只要在item被移除后,将itemView的透明度和高度比例设置回来即可。

09.暂停或停止加载数据优化

  • 问题

    • 比如用RecyclerView实现画廊,加载比较大的图片,如果快速滑动,则可能会出现卡顿,主要是加载图片需要时间
  • 如何解决RecyclerView实现画廊卡顿?

    • RecyclerView 滑动时不让 Glide 加载图片。滚动停止后才开始恢复加载图片。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //RecyclerView.SCROLL_STATE_IDLE //空闲状态
    //RecyclerView.SCROLL_STATE_FLING //滚动状态
    //RecyclerView.SCROLL_STATE_TOUCH_SCROLL //触摸后状态
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
    super.onScrollStateChanged(recyclerView, newState);
    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
    LoggerUtils.e("initRecyclerView"+ "恢复Glide加载图片");
    Glide.with(ImageBrowseActivity.this).resumeRequests();
    }else {
    LoggerUtils.e("initRecyclerView"+"禁止Glide加载图片");
    Glide.with(ImageBrowseActivity.this).pauseRequests();
    }
    }
    });

14.recyclerView优化

14.1 DiffUtil刷新优化

  • 分页拉取远端数据,对拉取下来的远端数据进行缓存,提升二次加载速度;对于新增或者删除数据通过 DiffUtil 来进行局部刷新数据,而不是一味地全局刷新数据。

14.2 布局优化

  • 减少 xml 文件 inflate 时间
    • 这里的 xml 文件不仅包括 layout 的 xml,还包括 drawable 的 xml,xml 文件 inflate 出 ItemView 是通过耗时的 IO 操作,尤其当 Item 的复用几率很低的情况下,随着 Type 的增多,这种 inflate 带来的损耗是相当大的,此时我们可以用代码去生成布局,即 new View() 的方式,只要搞清楚 xml 中每个节点的属性对应的 API 即可。
  • 减少 View 对象的创建
    • 一个稍微复杂的 Item 会包含大量的 View,而大量的 View 的创建也会消耗大量时间,所以要尽可能简化 ItemView;设计 ItemType 时,对多 ViewType 能够共用的部分尽量设计成自定义 View,减少 View 的构造和嵌套。

14.3 对itemView中孩子View的点击事件优化

  • 对于每个ViewHolder都要设置子View点击监听器怎么办?
    • 全局new一个Listener,通过view.getId与view.getTag取到对应View的id和数据,避免对每个新创建的ViewHolder都new出一个监听器,优化了对象的频繁创建带来的资源消耗。

14.4 复用RecycledViewPool

  • 如果RecycledView的adapter是一样的话可以考虑共享一个对象池。 比如说:RecycledView嵌套RecycledView,里面的RecycledView大部分都adapter都一样。
    • 具体该怎么封装???

14.5 RecyclerView预加载优化

14.6 RecyclerView嵌套滑动卡顿优化

  • RecycleView与NestedScrollView的嵌套