优化流程自定义view

RecycleView的复用和优化

2021-08-27  本文已影响0人  feifei_fly

最近了解了一下RecycleView的缓存机制,做了一些记录,防止遗忘

一、RecyleView四级缓存

image

首先明确RecyecleView中缓存的对象是ViewHolder.

Recycler负责管理和缓存所有的ViewHolder。
RecycleView的缓存从上到下分为四层:scrap、cache、ViewCacheExtension、RecycleViewPool

1.1、 scrap

scrap 用来缓存正在显示的ViewHolder。

scrap 分为两个集合:mAttachedScrap 和 mChangedScrap。

当我们调用 notifyItemRangeChanged 方法的时候,会触发 requestLayout 方法,就会重新布局,重新布局的话,就会先将 viewHolder 放到 scrap 中(屏幕上变化的放入mChangedScrap 中,其余的放入mAttachedScrap 中),然后 fill 布局的时候,再从 mAttachedScrap 里面取出来直接使用。mChangedScrap 中的 viewHolder 会被移动到 RecycledViewPool 中,所以 mChangedScrap 对应的 item 需要从 pool 中取对应的 viewHolder,然后重新绑定。

image

View中的detach和remove

Recycled View中的Scrap View

1.2、cached

数据结构mCachedViews,用于缓存从屏幕中移除,但是可能很快被再次显示的ViewHolder

1.3、ViewCacheExtension

这个是需要自定义的,而且使用有很大的限制,所以不深入介绍了。

1.4、RecycledViewPool

RecycledViewPool 储存各个类型的 viewHolder 它缓存的是被恢复出厂设置的viewHolder,需要重新调用bind 绑定数据。

RecycleView滑出屏幕时的ViewHolder的复用过程

image

滚出屏幕的View会优先保存到mCacheViews, 如果mCacheViews中保存满了,就会保存到RecyclerViewPool中。

二、Recycler 缓存加载流程

image

三、一些优化方法

3.1、 setHastFixedSize

当知道Adapter内Item的改变不会影响RecyclerView宽高的时候,可以设置为true让RecyclerView避免重新计算大小。

注意两点:

onItemRangeChanged(),

onItemRangeInserted(),

onItemRangeRemoved(),

onItemRangeMoved()

上面四个方法会调用triggerUpdateProcessor方法

    void triggerUpdateProcessor() {
            if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) {
                ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable);
            } else {
                mAdapterUpdateDuringMeasure = true;
                requestLayout();
            }
        }

会根据mHasFixedSize这个值来判断需要不需要requestLayout();

   public void onChanged() {
            assertNotInLayoutOrScroll(null);
            mState.mStructureChanged = true;

            processDataSetCompletelyChanged(true);
            if (!mAdapterHelper.hasPendingUpdates()) {
                requestLayout();
            }
        }

3.2、setHasStableIds

Adapter.setHasStablesId(true)开启固定ID

DemoAdapter  mAdapter=new DemoAdapter();
mAdapter.setHasStablesId(true);

在 Adapter 类中重写getItemId来给每个 Item 一个唯一的ID。

@Override
public long getItemId(int position){
    return items.get(position).getId();
}

setHasStableIds(true)之后,数据为发生变化情况下,滚动recycleView

ViewHolder会被缓存到mAttachedScrap中,复用时通过position 从mAttachedScrap直接取出显示,不需要重新createViewHolder、bindViewHolder

用空间换时间,
从而规避滑动recyelveView过程中出现的闪烁问题。

3.3、recycleView 图片列表快速刷新

recyleView 中显示图片列表,快速滑动容易出现卡顿。一个优化思路,可以设置在滑动过程中暂停正在加载的图片,滑动停止之后再恢复图片的加载。

recyceView?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                    Glide.with(requireActivity()).resumeRequests()
                } else {
                    Glide.with(requireActivity()).pauseRequests()
                }
            }
        })

参考文章:

https://www.jianshu.com/p/1d2213f303fc
https://blog.csdn.net/weixin_43130724/article/details/90068112
https://www.jianshu.com/p/4a2b18135447

https://zhuanlan.zhihu.com/p/80475040

https://www.jianshu.com/p/aeb9ccf6a5a4

图片闪烁问题分析:
https://www.jianshu.com/p/29352def27e6

上一篇 下一篇

猜你喜欢

热点阅读