精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

RecyclerView的緩存機制及使用策略

開發 前端
當RecyclerView不再需要某個ViewHolder時(例如,當列表項被完全移出屏幕并且緩存已滿時),ViewHolder會被放入RecycledViewPool并最終可能被系統回收。

RecyclerView的緩存機制是為了提高列表滾動時的性能。采用了多級緩存策略來存儲和復用視圖(View),減少視圖的創建和銷毀,進而減少內存分配和GC的頻率。

緩存層級

負責回收和復用ViewHolder的類是Recycler,負責緩存的主要就是這個類的幾個成員變量。

public final class Recycler {

    // 存放可見范圍內的 ViewHolder (但是在 onLayoutChildren 的時候,會將所有 View 都會緩存到這), 從這里復用的 ViewHolder 如果 position 或者 id 對應的上,則不需要重新綁定數據。
    final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
    // 存放可見范圍內并且數據發生了變化的 ViewHolder,從這里復用的 ViewHolder 需要重新綁定數據。
    ArrayList<ViewHolder> mChangedScrap = null;
    // 存放 remove 掉的 ViewHolder,從這里復用的 ViewHolder 如果 position 或者 id 對應的上,則不需要重新綁定數據。
    final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>(); 
    // 默認值是 2
    private int mRequestedCacheMax = DEFAULT_CACHE_SIZE; 
    // 默認值是 2
    int mViewCacheMax = DEFAULT_CACHE_SIZE; 

    // 存放 remove 掉,并且重置了數據的 ViewHolder,從這里復用的 ViewHolder 需要重新綁定數據。 // 默認值大小是 5 
    RecycledViewPool mRecyclerPool; 
    // 自定義的緩存
    private ViewCacheExtension mViewCacheExtension; 
    }

RecyclerView的緩存機制主要由四個部分組成,它們按照從高到低的優先級排列:

  1. 「Scrap緩存(Scrap Heap)」

包括mAttachedScrap和mChangedScrap,也稱為屏內緩存,因為它們主要用于保存屏幕內當前可見或者即將可見的ViewHolder。

mAttachedScrap:存放的是已添加到RecyclerView但與RecyclerView臨時分離(例如在滾動或布局調整過程中)的ViewHolder。

mChangedScrap:存放的是數據已改變但尚未重新綁定數據的ViewHolder,通常用于動畫播放等場景。

  1. 「Cache緩存(mCachedViews)」

又稱離屏緩存,用于保存最新被移除(remove)但尚未被回收的ViewHolder。

緩存的大小是有限制的,默認最大數量為2(由DEFAULT_CACHE_SIZE定義)。

當需要展示新視圖時,會首先檢查Cache緩存中是否有可用的ViewHolder。

  1. 「ViewCacheExtension」

為開發者預留的緩存池,允許開發者自定義緩存策略,存儲更多的或特定類型的ViewHolder。

開發者可以通過實現ViewCacheExtension接口來擴展緩存功能。

  1. 「RecycledViewPool(mRecyclerPool)」

終極的回收緩存池,用于存放被標識為廢棄(即其他緩存池不再需要的)的ViewHolder。

這些ViewHolder已經被抹除了數據,需要重新綁定數據才能使用。

RecycledViewPool會根據不同的item類型創建不同的List來存儲ViewHolder。

緩存使用策略

int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
        RecyclerView.State state, boolean stopOnFocusable) {
    // max offset we should set is mFastScroll + available
    final int start = layoutState.mAvailable;
    //首選該語句塊的判斷,判斷當前狀態是否為滾動狀態,如果是的話,則觸發 recycleByLayoutState 方法
    if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {
        // TODO ugly bug fix. should not happen
        if (layoutState.mAvailable < 0) {
            layoutState.mScrollingOffset += layoutState.mAvailable;
        }
        // 分析1----回收
        recycleByLayoutState(recycler, layoutState);
        }
    while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
        //分析2----復用
        layoutChunk(recycler, state, layoutState, layoutChunkResult);
    }
}

// 分析1----回收 
// 通過一步步追蹤,我們發現最后調用的是 removeAndRecycleViewAt() 
public void removeAndRecycleViewAt(int index, @NonNull Recycler recycler) {
    final View view = getChildAt(index);
    //分析1-1
    removeViewAt(index);
    //分析1-2
    recycler.recycleView(view);
}
// 分析1-1
// 從 RecyclerView 移除一個 View 
public void removeViewAt(int index) {
    final View child = getChildAt(index);
    if (child != null) {
        mChildHelper.removeViewAt(index);
    }
}
//分析1-2 
// recycler.recycleView(view) 最終調用的是 recycleViewHolderInternal(holder) 進行回收 VH (ViewHolder)
void recycleViewHolderInternal(ViewHolder holder) {
    if (forceRecycle || holder.isRecyclable()) {
        //判斷是否滿足放進 mCachedViews 
        if (mViewCacheMax > 0 && !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID| ViewHolder.FLAG_REMOVED| ViewHolder.FLAG_UPDATE| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)){
            // 判斷 mCachedViews 是否已滿
            if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
                // 如果滿了就將下標為0(即最早加入的)移除,同時將其加入到 RecyclerPool 中
                recycleCachedViewAt(0);
                cachedViewSize--;
                }  
            mCachedViews.add(targetCacheIndex, holder);
            cached = true;
            }
        //如果沒有滿足上面的條件,則直接存進 RecyclerPool 中    
        if (!cached) {
            addViewHolderToRecycledViewPool(holder, true);
            recycled = true;
         } 
     }
}

//分析2
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
        LayoutState layoutState, LayoutChunkResult result) {
    //分析2-1
    View view = layoutState.next(recycler);
    if (layoutState.mScrapList == null) {
        if (mShouldReverseLayout == (layoutState.mLayoutDirection
                == LayoutState.LAYOUT_START)) {
            //添加到 RecyclerView 上
            addView(view);
        } else {
            addView(view, 0);
        }
    }
}
//分析2-1
//layoutState.next(recycler) 最后調用的是 tryGetViewHolderForPositionByDeadline() 這個方法正是 復用 核心的方法
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
        boolean dryRun, long deadlineNs) {
    // 0) If there is a changed scrap, try to find from there
    // 例如:我們調用 notifyItemChanged 方法時
    if (mState.isPreLayout()) {
        // 如果是 changed 的 ViewHolder 那么就先從 mChangedScrap 中找
        holder = getChangedScrapViewForPosition(position);
        fromScrapOrHiddenOrCache = holder != null;
    }
    // 1) Find by position from scrap/hidden list/cache
    if (holder == null) {
        //如果在上面沒有找到(holder == null),那就嘗試從通過 pos 在 mAttachedScrap/ mHiddenViews / mCachedViews 中獲取
        holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
    }
    if (holder == null) {
        // 2) Find from scrap/cache via stable ids, if exists
        if (mAdapter.hasStableIds()) {
            //如果在上面沒有找到(holder == null),那就嘗試從通過 id 在 mAttachedScrap/ mCachedViews 中獲取
            holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
        }
        if (holder == null && mViewCacheExtension != null) {
            //這里是通過自定義緩存中獲取,忽略
        }
        //如果在上面都沒有找到(holder == null),那就嘗試在 RecycledViewPool 中獲取
        if (holder == null) { // fallback to pool
            holder = getRecycledViewPool().getRecycledView(type);
            if (holder != null) {
                //這里拿的是,要清空數據的
                holder.resetInternal();
            }
        }
        //如果在 Scrap / Hidden / Cache / RecycledViewPool 都沒有找到,那就只能創建一個了。
        if (holder == null) {
            holder = mAdapter.createViewHolder(RecyclerView.this, type);
        }
    }
    return holder;
}
  • 「RecyclerView滾動時」:首先移除滑出屏幕的item,并將這些ViewHolder存入Cache緩存(mCachedViews)。如果Cache緩存已滿,則將更舊的ViewHolder存入RecycledViewPool。
  • 「數據更新時」:如果屏幕內的某個item數據發生變化,但ViewHolder仍然可見,那么這個ViewHolder會被放入mChangedScrap。當需要重新綁定數據時,會從這個緩存中取出ViewHolder。
  • 「刪除item時」:被刪除的item對應的ViewHolder首先會進入Scrap緩存,然后可能會被移入Cache緩存或RecycledViewPool。

「注意」:當RecyclerView不再需要某個ViewHolder時(例如,當列表項被完全移出屏幕并且緩存已滿時),ViewHolder會被放入RecycledViewPool并最終可能被系統回收。

緩存機制的好處

  • 「減少視圖創建和銷毀」:通過復用已有的ViewHolder,大大減少視圖的創建和銷毀次數,從而節省內存和提高性能。
  • 「優化滾動性能」:當滾動列表時,由于大部分視圖都可以從緩存中快速獲取,可以保持流暢的滾動體驗。
  • 「降低GC頻率」:由于減少了視圖的創建和銷毀,也降低了GC的頻率,進一步提高了應用的性能。

責任編輯:武曉燕 來源: 沐雨花飛蝶
相關推薦

2021-03-29 11:51:07

緩存儲存數據

2018-11-30 09:03:55

HTTP緩存Web

2021-08-18 07:56:04

AndroidRecyclerVie復用

2022-05-10 08:58:56

CacheHTTP

2025-02-21 12:00:00

SpringBoot防重復提交緩存機制

2011-07-11 15:28:19

MySQL索引優化

2015-10-08 16:40:50

緩存頭像策略

2023-11-16 08:22:14

LruCacheAndroid

2013-08-02 14:19:50

Java日志緩存

2009-11-23 17:56:44

PHP緩存機制

2009-06-18 14:51:12

Hibernate緩存Hibernate

2009-06-17 15:43:03

Hibernate緩存

2023-02-24 16:46:25

Glide緩存機制

2023-05-04 16:10:13

緩存前端

2024-06-24 00:30:00

2025-02-05 12:22:21

2019-03-20 09:11:50

Web緩存策略

2018-07-12 15:30:03

HTTP緩存機制

2019-03-22 09:50:52

WebJavaScript前端

2025-01-02 14:50:34

MyBatis開發緩存
點贊
收藏

51CTO技術棧公眾號

中文字幕亚洲一区二区三区五十路| 欧美日韩亚洲一区二| 99视频日韩| 久久久久久久久久影院| 欧美精选一区二区三区| 欧美老女人在线| 精品无码国模私拍视频| 国产乱视频在线观看| 国产在线精品一区二区不卡了| 欧美日韩国产成人在线| 日本高清www| 警花av一区二区三区| 婷婷国产在线综合| 中文字幕久精品免| 姝姝窝人体www聚色窝| 麻豆视频观看网址久久| 国产69久久精品成人| 国产美女免费网站| avtt综合网| 欧美日韩不卡一区二区| 欧美日本视频在线观看| 成人免费观看视频大全| 久久精品视频免费| 亚洲xxxx18| 成人黄色免费网| 一本色道88久久加勒比精品| 精品国产欧美一区二区五十路 | av一区二区三区黑人| 成人日韩在线电影| 中文字幕在线日本| 亚洲欧洲一区二区天堂久久| 久久久国产精品免费| 日本精品在线观看视频| 日韩精品免费一区二区三区竹菊| 欧美高清激情brazzers| 亚洲污视频在线观看| 亚洲天堂av影院| 亚洲成人av一区| 亚洲爆乳无码精品aaa片蜜桃| aaa在线观看| 国产蜜臀97一区二区三区| 久久亚洲综合网| 天堂在线中文| thepron国产精品| 国产经典一区二区三区| 国产高清视频免费观看| 国产综合色产在线精品| 国产日韩精品视频| 中文字幕乱码一区二区| 日韩精品欧美精品| 国产精品av在线| 亚洲精品一区二三区| 久久久天天操| 国产999精品久久久影片官网| 日韩精品在线免费视频| 中文久久精品| 日韩av电影在线播放| 亚洲黄网在线观看| 日日欢夜夜爽一区| 国产精品久久久久久久久久东京 | 91精品国产一区二区| 亚洲一区二区三区四区五区| 欧美激情福利| 91精品国产免费| 亚洲少妇一区二区| 99re热精品视频| 欧美不卡一区二区三区四区| xxxx视频在线观看| 凹凸av导航大全精品| 精品久久久久久无| 精品国产一区在线| 欧美精品momsxxx| 伊人精品在线观看| 国产一区二区视频在线观看免费| 欧美久久一区| 青草青草久热精品视频在线网站| 91麻豆精品在线| 精品一区二区在线看| 国产成人精品福利一区二区三区| 欧洲精品久久一区二区| 久久女同性恋中文字幕| 日韩福利视频| 中文国产字幕在线观看| 欧美日韩国产综合新一区| 亚洲一区二区蜜桃| 亚洲啊v在线免费视频| 亚洲精品自产拍| 黄色免费一级视频| 尹人成人综合网| 国产成人精品最新| 国产成人精品白浆久久69| 99re这里都是精品| 亚洲精品一区二区三区av| 高h视频在线观看| 欧美日韩国产色视频| 天天干天天av| 少妇久久久久| 久久亚洲欧美日韩精品专区 | 免费永久网站黄欧美| 国产日韩欧美成人| 水中色av综合| 一区二区三区中文字幕在线观看| 18禁男女爽爽爽午夜网站免费| 欧美日韩破处视频| 亚洲美女视频网| 午夜国产福利一区二区| 免费一区视频| 高清日韩一区| 免费a级在线播放| 欧美视频在线免费看| 国产美女视频免费看| 亚洲欧洲免费| 国内自拍欧美激情| 国产婷婷在线视频| 国产三级精品三级在线专区| 国产高清av在线播放| 精品入口麻豆88视频| 国产亚洲日本欧美韩国| 国产污污视频在线观看| 国产精选一区二区三区| 亚洲午夜精品久久久久久浪潮| 欧美aa在线观看| 欧美大片一区二区| 老熟妇高潮一区二区三区| 日韩激情av在线| 精品亚洲欧美日韩| 丁香花在线观看完整版电影| 91精品婷婷国产综合久久| 69xxx免费| 久久三级视频| 欧美三级电影在线播放| 丝袜老师在线| 亚洲精品电影在线| 国产一级淫片免费| 国产成人在线视频免费播放| 国产又爽又黄ai换脸| 国内自拍亚洲| 在线日韩欧美视频| 特级西西444www大胆免费看| 久久久久久久精| 91成人在线观看喷潮教学| 国产成人福利av| 欧美激情精品久久久久久久变态| 国产精品欧美激情在线| 中文字幕在线不卡一区| 亚洲污视频在线观看| 四季av在线一区二区三区| 国产精品无av码在线观看| 成人午夜在线观看视频| 欧美中文字幕一区二区三区亚洲| 熟女俱乐部一区二区视频在线| 亚洲一区二区动漫| 蜜桃麻豆91| 欧美色网在线| 在线成人激情黄色| 国产精品女人久久久| 亚洲女子a中天字幕| 亚洲AV无码久久精品国产一区| 欧美一区二区三区另类| 成人在线资源网址| 激情国产在线| 国产一区二区三区中文| 夜夜爽8888| 亚洲欧美成人一区二区三区| 免费不卡的av| 久久久久久久波多野高潮日日| 日韩色妇久久av| 精品视频91| 97视频在线播放| 国产粉嫩一区二区三区在线观看 | 日本女人黄色片| 黄色欧美成人| 欧美日韩精品一区| 国产一区精品福利| 欧美精品日韩三级| 水中色av综合| 欧美高清激情brazzers| 国产第100页| 欧美激情在线一区二区| 日本成人xxx| 亚洲一区二区毛片| 亚洲精品在线视频观看| 视频二区欧美| 日韩av片永久免费网站| 超碰在线观看免费| 日韩高清免费在线| 91影院在线播放| 亚洲成av人片在线观看无码| 亚洲黄色免费视频| 国产99一区视频免费| 亚洲熟妇av一区二区三区漫画| 欧美性感美女一区二区| 成人免费视频网站入口| 亚洲第一二三四区| 久久99久久久久久久噜噜| 免费黄网站在线观看| 7777精品伊人久久久大香线蕉最新版 | 成人久久精品人妻一区二区三区| 色狠狠一区二区三区香蕉| 日韩视频中文字幕在线观看| 久久久一区二区| 免费黄色a级片| 精品夜夜嗨av一区二区三区| 欧美日韩在线视频一区二区三区| 午夜精品久久久久久久四虎美女版| 国产伦精品一区二区| 欧洲午夜精品| 欧美一级黑人aaaaaaa做受| 182tv在线播放| 在线国产精品播放| 香蕉av在线播放| 欧美成人福利视频| 国产理论片在线观看| 色婷婷综合激情| 国产精品二区一区二区aⅴ| 国产精品视频免费看| 欧美成人午夜精品免费| 成人av在线一区二区| 成人免费黄色av| 美女性感视频久久| 成人3d动漫一区二区三区| 亚洲黄网站黄| 中文精品无码中文字幕无码专区| 日韩久久视频| 日韩欧美一区二区在线观看| 五月天亚洲色图| 国精产品99永久一区一区| 一区二区三区免费在线看| 51国产成人精品午夜福中文下载| 欧美一级免费| 国产欧美精品一区二区| 久久久久伊人| 国产欧美中文字幕| 国外成人福利视频| 国产精品免费视频久久久| 希岛爱理一区二区三区av高清| 2020国产精品视频| 岛国av免费在线观看| 国内精品一区二区三区| 久久香蕉av| 欧美精品福利在线| 电影k8一区二区三区久久| 久久99国产精品自在自在app| 国产超级va在线视频| 伦伦影院午夜日韩欧美限制| av在线播放国产| 久久国产精品电影| 在线观看三级视频| 久久91精品国产91久久跳| 久久久久黄久久免费漫画| 久久久在线免费观看| cao在线视频| 国产99久久精品一区二区永久免费| 玛雅亚洲电影| 国产精品自拍小视频| 四虎在线精品| 91传媒在线免费观看| 成人免费在线电影网| 久久国产手机看片| 国产日韩视频在线| 一区二区三区欧美在线| 在线看片不卡| 久久精品视频16| 日韩av午夜在线观看| 毛片毛片毛片毛| 国产乱码精品一品二品| 欧美大喷水吹潮合集在线观看| 99re热这里只有精品视频| 一区二区三区四区免费| 国产精品拍天天在线| 欧美极品视频在线观看| 精品电影在线观看| 中文字幕+乱码+中文| 91精品国产91久久综合桃花 | 自拍偷拍亚洲在线| yellow91字幕网在线| 午夜精品三级视频福利| 成人自拍av| 亚洲xxxx做受欧美| 亚洲精品亚洲人成在线| 一区二区不卡在线观看| 影音先锋中文字幕一区| 精品久久久噜噜噜噜久久图片| 精品午夜久久福利影院| 男男做爰猛烈叫床爽爽小说 | 一区二区三区av在线| 欧美日韩精品一本二本三本 | 丁香婷婷综合网| 亚洲av无码一区二区三区人| 专区另类欧美日韩| 国产精品一区二区6| 欧美日韩另类国产亚洲欧美一级| www.精品久久| 亚洲一区二区国产| 欧洲在线视频| 国产精品日日摸夜夜添夜夜av| 视频二区欧美毛片免费观看| 日韩av影视| 激情自拍一区| 一二三级黄色片| 久久亚洲捆绑美女| 久草视频免费在线| 欧美精品视频www在线观看| 天天干天天摸天天操| 俺也去精品视频在线观看| 欧美大胆成人| 国产欧美丝袜| 一个色综合网| 日本爱爱免费视频| 91亚洲精品久久久蜜桃| 欧美黄片一区二区三区| 欧美日韩黄色一区二区| 日本精品专区| 91成人在线观看国产| 精品午夜视频| 亚洲国产另类久久久精品极度| 国产欧美一区二区三区国产幕精品| 又色又爽又黄视频| 中文成人av在线| 自拍偷拍18p| 亚洲精品wwwww| 成人在线免费观看黄色| 91久久久一线二线三线品牌| 国产精品久久久久久久| 一区二区三区韩国| 国产亚洲精品精华液| 91av在线免费视频| 精品盗摄一区二区三区| 免费在线观看av电影| 91欧美精品成人综合在线观看| 成人嘿咻视频免费看| 嫩草av久久伊人妇女超级a| 91香蕉视频污在线| 中文字幕在线观看视频网站| 亚洲高清久久久久久| 国产激情在线播放| 国产免费一区| 国产一区二区精品| 特大黑人巨人吊xxxx| 精品免费在线观看| 五月婷婷深深爱| 奇门遁甲1982国语版免费观看高清| 爽爽窝窝午夜精品一区二区| 国产美女网站在线观看| 91丨九色丨蝌蚪丨老版| 69亚洲精品久久久蜜桃小说 | 欧美一区二区久久| 成人在线播放免费观看| 91在线免费看网站| 欧美成人tv| 国产视频精品视频| 欧美日韩中文字幕综合视频| 桃花色综合影院| 国产成人一区二| 热久久天天拍国产| 三年中文在线观看免费大全中国| 亚洲桃色在线一区| 亚洲爱情岛论坛永久| 国外视频精品毛片| 久久99国内| 久久久精品高清| 亚洲欧美另类图片小说| 成人毛片在线精品国产| 欧美一级片在线播放| 欧美日韩在线播放视频| 污污的视频免费观看| 亚洲影院理伦片| 色视频在线观看福利| 国产精品久久久久久久av大片| 久久久久av| 国产伦精品一区二区免费| 欧美午夜美女看片| 免费黄色在线| 国产精品国产三级欧美二区 | 久久久久电影| 日韩成人av一区二区| 欧美性淫爽ww久久久久无| av网站在线免费| 免费日韩av电影| 韩国理伦片一区二区三区在线播放 | 中文字幕视频三区| 亚洲午夜视频在线| av资源种子在线观看| 99理论电影网| 丝袜亚洲另类丝袜在线| 一区二区视频免费看| 亚洲精品在线91| 国产一区二区三区| 欧美国产激情视频| 亚洲欧洲综合另类| 九九在线视频| 成人在线看片| 日本免费新一区视频 | 91福利社在线观看| 污影院在线观看| 天堂精品一区二区三区| 成人va在线观看| 国产露脸无套对白在线播放| 日产日韩在线亚洲欧美| 最新国产乱人伦偷精品免费网站|