日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

小葵花妈妈课堂开课了《RecyclerView 复用解析》

發(fā)布時(shí)間:2023/12/18 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小葵花妈妈课堂开课了《RecyclerView 复用解析》 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最新項(xiàng)目遇到一個(gè)問題,就是RecycleView的itemview會(huì)頻繁拉取圖片,同一時(shí)間多次拉取同一張照片。
初探,是因?yàn)樵搱?chǎng)景notifyDataSetChanged()過于頻繁,一秒鐘會(huì)調(diào)用5次左右,
導(dǎo)致ViewHolder沒有復(fù)用,也不是沒有復(fù)用而是復(fù)用的并沒有像理想中的樣式。

notify

  • notifyDataSetChanged
  • mObservable.notifyChanged()
  • mObservers.get(i).onChanged();
  • setDataSetChangedAfterLayout();
    4.1.1 markKnownViewsInvalid
    //1 Mark all known views as invalid,僅標(biāo)記可見的布局為ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
    //2 mAdapter.hasStableIds() true -> mCachedViews 標(biāo)記 ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID
    //3 mAdapter.hasStableIds() false -> addViewHolderToRecycledViewPool ->getRecycledViewPool().putRecycledView(holder); AND mCachedViews.clear();
    // we cannot re-use cached views in this case. Recycle them all
    4.1.2 markItemDecorInsetsDirty
    //child.getLayoutParams()).mInsetsDirty = true;
    //mCachedViews layoutParams.mInsetsDirty = true;
  • requestLayout();
  • 回收邏輯

  • void onLayout(boolean changed, int l, int t, int r, int b)
  • dispatchLayout()
  • void dispatchLayoutStep2()
  • void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
  • detachAndScrapAttachedViews(recycler); //先回收,在fill,也就是后去查找可以復(fù)用的holder。僅處理children holder
  • scrapOrRecycleView(recycler, i, v);
    6.1 viewHolder.isInvalid() && !viewHolder.isRemoved() && !mRecyclerView.mAdapter.hasStableIds() -->
    6.1.1 true recycler.recycleViewHolderInternal(viewHolder);
    addViewHolderToRecycledViewPool(holder, true); //最終放入getRecycledViewPool()
    6.1.2 false scrapView(View view)
    holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID) || !holder.isUpdated() || canReuseUpdatedViewHolder(holder) -->
    6.1.2.1 true mAttachedScrap.add(holder);
    6.1.2.2 false mChangedScrap.add(holder);
    總結(jié):如果Holder無效最終放入getRecycledViewPool,否則mAttachedScrap
  • 回收另外一個(gè)分支

  • onLayout
  • dispatchLayout
  • dispatchLayoutStep3
  • removeAndRecycleScrapInt //僅處理mAttachedScrap所緩存Holder
    vh.setIsRecyclable(true);
  • recycler.quickRecycleScrapView(scrap);
  • recycleViewHolderInternal(ViewHolder holder)
    forceRecycle || holder.isRecyclable() 成立
    (mViewCacheMax > 0 && !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) 不成立,包含ViewHolder.FLAG_INVALID
  • addViewHolderToRecycledViewPool(ViewHolder holder, boolean dispatchRecycled)
  • getRecycledViewPool().putRecycledView(holder); 最終放到了getRecycledViewPool中。
  • 查找可復(fù)用Holder過程

  • void onLayout(boolean changed, int l, int t, int r, int b)
  • dispatchLayout()
  • void dispatchLayoutStep2()
  • void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
  • fill(RecyclerView.Recycler recycler, LayoutState layoutState,
    RecyclerView.State state, boolean stopOnFocusable)
  • layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
    LayoutState layoutState, LayoutChunkResult result)
  • LinerLayout.next
  • getViewForPosition
  • tryGetViewHolderForPositionByDeadline
    9.1 isPreLayout() --> getChangedScrapViewForPosition(int position) //如果是pre-layout,會(huì)從mChangedScrap獲取復(fù)用
    9.2 getScrapOrHiddenOrCachedHolderForPosition(position, dryRun)
    9.2.1 mAttachedScrap 首先從該處獲取,
    9.2.2 mChildHelper.findHiddenNonRemovedView(position) 拿到隱藏的ViewHolder
    9.2.3 mCachedViews //Search in our first-level recycled view cache. 最后從一級(jí)緩存獲取
    // invalid view holders may be in cache if adapter has stable ids as they can be
    // retrieved via getScrapOrCachedViewForId
    // 通過原廠注釋可以知道,has stable才可以使用mCachedViews緩存。在回收處也可以看出。
    9.2.4 mAdapter.hasStableIds() --> getScrapOrCachedViewForId() //仍然需要hasStableIds
    // 首先mAttachedScrap
    // 之后mCachedViews
    9.3 mViewCacheExtension //外部擴(kuò)展
    9.4 getRecycledViewPool().getRecycledView(type) //此處查到holder被resetInternal,即需要重新bind
    9.5 mAdapter.createViewHolder(RecyclerView.this, type); //最后,create
  • bind過程

  • tryGetViewHolderForPositionByDeadline(int position,
    boolean dryRun, long deadlineNs)
  • tryBindViewHolderByDeadline
  • mAdapter.bindViewHolder(holder, offsetPosition);
  • 至此RecyclerView的復(fù)用機(jī)制已經(jīng)差不多了。至此也看到了我的問題也出現(xiàn)了答案的線索。
    因?yàn)槭莕otifyDataSetChanged出發(fā)的刷新,會(huì)將所有ViewHolder標(biāo)記為FLAG_INVALID。
    在回收ViewHolder時(shí),會(huì)放入getRecycledViewPool中。
    RecycledViewPool官方注釋

    RecycledViewPool lets you share Views between multiple RecyclerViews.
    If you want to recycle views across RecyclerViews, create an instance of RecycledViewPool
    and use {@link RecyclerView#setRecycledViewPool(RecycledViewPool)}.
    RecyclerView automatically creates a pool for itself if you don’t provide one.

    作用為多個(gè)RecyclerViews之間復(fù)用ViewHolder。
    可以通過setRecycledViewPool進(jìn)行設(shè)置。
    SparseArray mScrap = new SparseArray<>(); 用來存儲(chǔ)不同類型的ViewHolder

    static class ScrapData {ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();int mMaxScrap = DEFAULT_MAX_SCRAP;long mCreateRunningAverageNs = 0;long mBindRunningAverageNs = 0; }

    默認(rèn)mMaxScrap大小為5個(gè)

    private static final int DEFAULT_MAX_SCRAP = 5;

    也就是做多存儲(chǔ)5個(gè)。我的項(xiàng)目正好有6個(gè)Item顯示,就導(dǎo)致只能存儲(chǔ) 1,2,3,4,5 而0沒有進(jìn)行存儲(chǔ)
    onBind的時(shí)候就會(huì)出現(xiàn)0 - 綁定 1,1 綁定2… 的問題。

    解決辦法為通過
    new一個(gè)RecyclerView.RecycledViewPool, 并設(shè)置recycledViewPool.setMaxRecycledViews(0, 6);
    第一個(gè)參數(shù)viewType,我這里僅有一種type,所以就寫0
    最終通過mRecycleList.setRecycledViewPool(recycledViewPool); 設(shè)置RecycledViewPool。
    至此大工告成。

    RecyclerView源碼有1w多行。剛看的時(shí)候無從下手,向其他博主所說的見森林而不見樹木。
    我就是從notifyDataSetChanged 和 onBindViewHolder入手,查找上下邏輯從而追蹤定位問題。

    總結(jié)

    以上是生活随笔為你收集整理的小葵花妈妈课堂开课了《RecyclerView 复用解析》的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。