recyclerview據官方的介紹,該控制項用於在有限的視窗中展示大量資料集,其實這樣功能的控制項我們並不陌生,例如:listview、gridview。recyclerview可以用來代替傳統的listview,gridview,更加強大和靈活。recyclerview的使用網上有非常多案例,這裡就不多說了,我們今天主要來看看recyclerview 的快取機制。
recycler是recyclerview的乙個內部類。我們來看一下它的主要的成員變數。
mchangedscrap 表示資料已經改變的ewholder列表
mattachedscrap 未與recyclerview分離的viewholder列表
mcachedviews viewholder快取列表,其大小由mviewcachemax決定,預設default_cache_size為2,可動態設定。
mviewcacheextension 開發者可自定義的一層快取,是虛擬類viewcacheextension的乙個例項,開發者可實現方法getviewforpositionandtype(recycler recycler, int position, int type)來實現自己的快取。
mrecyclerpool viewholder快取池,在有限的mcachedviews中如果存不下viewholder時,就會把viewholder存入recyclerviewpool中。
我們來看一張recyclerview 快取機制的流程圖,如下圖
貼上原始碼,如下。我們根據流程圖和原始碼來分析recyclerview的快取機制。
public view getviewforposition(int position) // 第一種 通過 position來查詢 for (int i = 0; i < changedscrapsize; i++) } //第二種 通過 id來查詢 if (madapter.hasstableids()) } } } return null; }
主流程 2
我們看一下主流程第19行**。
holder = getscrapviewforposition(position, invalid_type, dryrun);
通過position查詢廢棄的holder,我們來看一下getscrapviewforposition方法內部實現,主要通過3種方法獲取holder快取。
第一種從mattachedscrap中通過匹配position獲取holder快取。
第二種通過childhelper找到隱藏但是沒有被移除的view,通過getchildviewholderint(view)方法獲取holder快取。
第三種從mcachedviews中通過匹配position獲取holder快取。
getscrapviewforposition原始碼如下
viewholder getscrapviewforposition(int position, int type, boolean dryrun) holder.addflags(viewholder.flag_returned_from_scrap); return holder; } } //通過childhelper找到隱藏但是沒有被移除的view,通過getchildviewholderint(view)方法獲取holder快取。 if (!dryrun) mchildhelper.detachviewfromparent(layoutindex); scrapview(view); vh.addflags(viewholder.flag_returned_from_scrap | viewholder.flag_bounced_from_hidden_list); return vh; } } // search in our first-level recycled view cache. //第三種從mcachedviews中通過匹配position獲取holder快取。 final int cachesize = mcachedviews.size(); for (int i = 0; i < cachesize; i++) if (debug) return holder; } } return null; }
主流程 3
我們看一下主流程第52行**。
holder = getscrapviewforid(madapter.getitemid(offsetposition), type, dryrun);
通過id獲取holder快取,getscrapviewforid方法內部主要通過2種方法獲取holder快取。
第一種從mattachedscrap中通過匹配id獲取holder快取。
第二種從mcachedviews中通過匹配id獲取holder快取。
getscrapviewforid方法原始碼如下。
viewholder getscrapviewforid(long id, int type, boolean dryrun) else if (holder.shouldignore())
}
主流程 5
我們看一下主流程第83行**。
holder = getrecycledviewpool().getrecycledview(type);
通過recyclerview 的viewholder快取池獲取holder。
通過holder.resetinternal();方法將holder復位,為後續重新繫結做好準備。
主流程 6
我們看一下主流程第92行**。
holder = madapter.createviewholder(recyclerview.this, type);建立新的holder
主流程 7
我們看一下主流程第119行**。
if (!holder.isbound() || holder.needsupdate() || holder.isinvalid())
判斷是否要重新繫結viewholder。
主流程就是這樣了。
經過上面的分析,我們可以看出recyclerview 快取機制(recycler)大致可以分為5級。
第一級 通過mchangedscrap匹配 position或者id獲取holder快取。
第二級 從mattachedscrap中通過匹配position獲取holder快取,或者通過childhelper找到隱藏但是沒有被移除的view,通過getchildviewholderint(view)方法獲取holder快取,或者
從mcachedviews中通過匹配position獲取holder快取。
第** 從mattachedscrap中通過匹配id獲取holder快取,或者
從mcachedviews中通過匹配id獲取holder快取。
第四級 從viewcacheextension獲取holder快取。
第五級 通過recyclerview 的viewholder快取池獲取holder。
最後有什麼理解不對的地方請大家多多指教。謝謝。
RecyclerView快取初識
what is recyclerview aflexibleview for providing alimitedwindow into alargedata set recyclerview layout manager item animator adapter what is viewhold...
Django QuerySet快取和惰性機制
惰性機制 在內部。queryset在構造,過濾,切片,傳遞的時候通常查詢集不會真正的去資料庫查詢 那它會在什麼情況下去資料庫查詢呢?1.迭代 通過迴圈將值乙個個拿出來 2.切片,使用切片語法的step 步長切片 引數,或者是切片只切出乙個元素的時候,django將執行資料庫查詢,3.直接在控制台列印...
recyclerView動畫解讀
我彷彿在逗我笑,就算繼承了,還是要呼叫setanimator方法,這樣還是會建立viewholder 那麼,自己給view設定動畫是否可以呢?我們知道,recyclerview是通過notifyitem來改變item的狀態的,這就是傳說中的觀察者模式,那麼我們沒有 notifyitemchanged...