Android ListView itemType使用Holder原理簡單分析
之前寫過一篇關於Holder複用原理的文章《Android ListView使用Holder優化原理》,此篇著重分析RecycleBin資料結構
原始碼在AbsListView中,RecycleBin一共有兩個儲存結構分別是ActiveViews 和 ScrapViews
ActiveViews儲存當前在介面(手機顯示區域)中顯示View,移出介面會存入ScrapViews ScrapViews儲存當前已經滑動出當前介面(手機顯示區域)顯示的View,這些view儲存起來相當於回收,當再次請求的時候從此儲存中取出反覆使用/** * The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of * storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the * start of a layout. By construction, they are displaying current information. At the end of * layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that * could potentially be used by the adapter to avoid allocating views unnecessarily. * * @see android.widget.AbsListView#setRecyclerListener(android.widget.AbsListView.RecyclerListener) * @see android.widget.AbsListView.RecyclerListener */ class RecycleBin { private RecyclerListener mRecyclerListener; /** * The position of the first view stored in mActiveViews. */ private int mFirstActivePosition; /** * Views that were on screen at the start of layout. This array is populated at the start of * layout, and at the end of layout all view in mActiveViews are moved to mScrapViews. * Views in mActiveViews represent a contiguous range of Views, with position of the first * view store in mFirstActivePosition. */ private View[] mActiveViews = new View[0]; /** * Unsorted views that can be used by the adapter as a convert view. */ private ArrayList<View>[] mScrapViews; private int mViewTypeCount; private ArrayList<View> mCurrentScrap; private ArrayList<View> mSkippedScrap; private SparseArray<View> mTransientStateViews; public void setViewTypeCount(int viewTypeCount) { if (viewTypeCount < 1) { throw new IllegalArgumentException("Can't have a viewTypeCount < 1"); } //noinspection unchecked ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount]; for (int i = 0; i < viewTypeCount; i++) { scrapViews[i] = new ArrayList<View>(); } mViewTypeCount = viewTypeCount; mCurrentScrap = scrapViews[0]; mScrapViews = scrapViews; } public void markChildrenDirty() { if (mViewTypeCount == 1) { final ArrayList<View> scrap = mCurrentScrap; final int scrapCount = scrap.size(); for (int i = 0; i < scrapCount; i++) { scrap.get(i).forceLayout(); } } else { final int typeCount = mViewTypeCount; for (int i = 0; i < typeCount; i++) { final ArrayList<View> scrap = mScrapViews[i]; final int scrapCount = scrap.size(); for (int j = 0; j < scrapCount; j++) { scrap.get(j).forceLayout(); } } } if (mTransientStateViews != null) { final int count = mTransientStateViews.size(); for (int i = 0; i < count; i++) { mTransientStateViews.valueAt(i).forceLayout(); } } } public boolean shouldRecycleViewType(int viewType) { return viewType >= 0; } /** * Clears the scrap heap. */ void clear() { if (mViewTypeCount == 1) { final ArrayList<View> scrap = mCurrentScrap; final int scrapCount = scrap.size(); for (int i = 0; i < scrapCount; i++) { removeDetachedView(scrap.remove(scrapCount - 1 - i), false); } } else { final int typeCount = mViewTypeCount; for (int i = 0; i < typeCount; i++) { final ArrayList<View> scrap = mScrapViews[i]; final int scrapCount = scrap.size(); for (int j = 0; j < scrapCount; j++) { removeDetachedView(scrap.remove(scrapCount - 1 - j), false); } } } if (mTransientStateViews != null) { mTransientStateViews.clear(); } } /** * Fill ActiveViews with all of the children of the AbsListView. * * @param childCount The minimum number of views mActiveViews should hold * @param firstActivePosition The position of the first view that will be stored in * mActiveViews */ void fillActiveViews(int childCount, int firstActivePosition) { if (mActiveViews.length < childCount) { mActiveViews = new View[childCount]; } mFirstActivePosition = firstActivePosition; final View[] activeViews = mActiveViews; for (int i = 0; i < childCount; i++) { View child = getChildAt(i); AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams(); // Don't put header or footer views into the scrap heap if (lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { // Note: We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views. // However, we will NOT place them into scrap views. activeViews[i] = child; } } } /** * Get the view corresponding to the specified position. The view will be removed from * mActiveViews if it is found. * * @param position The position to look up in mActiveViews * @return The view if it is found, null otherwise */ View getActiveView(int position) { int index = position - mFirstActivePosition; final View[] activeViews = mActiveViews; if (index >=0 && index < activeViews.length) { final View match = activeViews[index]; activeViews[index] = null; return match; } return null; } View getTransientStateView(int position) { if (mTransientStateViews == null) { return null; } final int index = mTransientStateViews.indexOfKey(position); if (index < 0) { return null; } final View result = mTransientStateViews.valueAt(index); mTransientStateViews.removeAt(index); return result; } /** * Dump any currently saved views with transient state. */ void clearTransientStateViews() { if (mTransientStateViews != null) { mTransientStateViews.clear(); } } /** * @return A view from the ScrapViews collection. These are unordered. */ View getScrapView(int position) { if (mViewTypeCount == 1) { return retrieveFromScrap(mCurrentScrap, position); } else { int whichScrap = mAdapter.getItemViewType(position); if (whichScrap >= 0 && whichScrap < mScrapViews.length) { return retrieveFromScrap(mScrapViews[whichScrap], position); } } return null; } /** * Put a view into the ScrapViews list. These views are unordered. * * @param scrap The view to add */ void addScrapView(View scrap, int position) { AbsListView.LayoutParams lp = (AbsListView.LayoutParams) scrap.getLayoutParams(); if (lp == null) { return; } lp.scrappedFromPosition = position; // Don't put header or footer views or views that should be ignored // into the scrap heap int viewType = lp.viewType; final boolean scrapHasTransientState = scrap.hasTransientState(); if (!shouldRecycleViewType(viewType) || scrapHasTransientState) { if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER || scrapHasTransientState) { if (mSkippedScrap == null) { mSkippedScrap = new ArrayList<View>(); } mSkippedScrap.add(scrap); } if (scrapHasTransientState) { if (mTransientStateViews == null) { mTransientStateViews = new SparseArray<View>(); } scrap.dispatchStartTemporaryDetach(); mTransientStateViews.put(position, scrap); } return; } scrap.dispatchStartTemporaryDetach(); if (mViewTypeCount == 1) { mCurrentScrap.add(scrap); } else { mScrapViews[viewType].add(scrap); } scrap.setAccessibilityDelegate(null); if (mRecyclerListener != null) { mRecyclerListener.onMovedToScrapHeap(scrap); } } /** * Finish the removal of any views that skipped the scrap heap. */ void removeSkippedScrap() { if (mSkippedScrap == null) { return; } final int count = mSkippedScrap.size(); for (int i = 0; i < count; i++) { removeDetachedView(mSkippedScrap.get(i), false); } mSkippedScrap.clear(); } /** * Move all views remaining in mActiveViews to mScrapViews. */ void scrapActiveViews() { final View[] activeViews = mActiveViews; final boolean hasListener = mRecyclerListener != null; final boolean multipleScraps = mViewTypeCount > 1; ArrayList<View> scrapViews = mCurrentScrap; final int count = activeViews.length; for (int i = count - 1; i >= 0; i--) { final View victim = activeViews[i]; if (victim != null) { final AbsListView.LayoutParams lp = (AbsListView.LayoutParams) victim.getLayoutParams(); int whichScrap = lp.viewType; activeViews[i] = null; final boolean scrapHasTransientState = victim.hasTransientState(); if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) { // Do not move views that should be ignored if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER || scrapHasTransientState) { removeDetachedView(victim, false); } if (scrapHasTransientState) { if (mTransientStateViews == null) { mTransientStateViews = new SparseArray<View>(); } mTransientStateViews.put(mFirstActivePosition + i, victim); } continue; } if (multipleScraps) { scrapViews = mScrapViews[whichScrap]; } victim.dispatchStartTemporaryDetach(); lp.scrappedFromPosition = mFirstActivePosition + i; scrapViews.add(victim); victim.setAccessibilityDelegate(null); if (hasListener) { mRecyclerListener.onMovedToScrapHeap(victim); } } } pruneScrapViews(); } /** * Makes sure that the size of mScrapViews does not exceed the size of mActiveViews. * (This can happen if an adapter does not recycle its views). */ private void pruneScrapViews() { final int maxViews = mActiveViews.length; final int viewTypeCount = mViewTypeCount; final ArrayList<View>[] scrapViews = mScrapViews; for (int i = 0; i < viewTypeCount; ++i) { final ArrayList<View> scrapPile = scrapViews[i]; int size = scrapPile.size(); final int extras = size - maxViews; size--; for (int j = 0; j < extras; j++) { removeDetachedView(scrapPile.remove(size--), false); } } if (mTransientStateViews != null) { for (int i = 0; i < mTransientStateViews.size(); i++) { final View v = mTransientStateViews.valueAt(i); if (!v.hasTransientState()) { mTransientStateViews.removeAt(i); i--; } } } } /** * Puts all views in the scrap heap into the supplied list. */ void reclaimScrapViews(List<View> views) { if (mViewTypeCount == 1) { views.addAll(mCurrentScrap); } else { final int viewTypeCount = mViewTypeCount; final ArrayList<View>[] scrapViews = mScrapViews; for (int i = 0; i < viewTypeCount; ++i) { final ArrayList<View> scrapPile = scrapViews[i]; views.addAll(scrapPile); } } } /** * Updates the cache color hint of all known views. * * @param color The new cache color hint. */ void setCacheColorHint(int color) { if (mViewTypeCount == 1) { final ArrayList<View> scrap = mCurrentScrap; final int scrapCount = scrap.size(); for (int i = 0; i < scrapCount; i++) { scrap.get(i).setDrawingCacheBackgroundColor(color); } } else { final int typeCount = mViewTypeCount; for (int i = 0; i < typeCount; i++) { final ArrayList<View> scrap = mScrapViews[i]; final int scrapCount = scrap.size(); for (int j = 0; j < scrapCount; j++) { scrap.get(j).setDrawingCacheBackgroundColor(color); } } } // Just in case this is called during a layout pass final View[] activeViews = mActiveViews; final int count = activeViews.length; for (int i = 0; i < count; ++i) { final View victim = activeViews[i]; if (victim != null) { victim.setDrawingCacheBackgroundColor(color); } } } } static View retrieveFromScrap(ArrayList<View> scrapViews, int position) { int size = scrapViews.size(); if (size > 0) { // See if we still have a view for this position. for (int i=0; i<size; i++) { View view = scrapViews.get(i); if (((AbsListView.LayoutParams)view.getLayoutParams()) .scrappedFromPosition == position) { scrapViews.remove(i); return view; } } return scrapViews.remove(size - 1); } else { return null; } }
相關推薦
Android熱補丁原理簡單分析與問題思考
Android熱補丁(熱修復)從2016年微信的Tinker開源後掀起了一個熱潮。時隔一年,阿里推出《深入探索android熱修復技術原理》技術書籍,在推廣其Sophix的同時非常詳細地描述了其方案的實現過程,以及遇到的各種坑,引來大家的關注與分析。可以看到大公
Android ListView itemType使用Holder原理簡單分析
之前寫過一篇關於Holder複用原理的文章《Android ListView使用Holder優化原理》,此篇著重分析RecycleBin資料結構 原始碼在AbsListView中,RecycleBin一共有兩個儲存結構分別是ActiveViews 和 ScrapVie
DWM1000 測距原理簡單分析
DWM1000 超寬頻測距,使用的TOF(time of fly) 的方式,也就是計算無線電磁波傳輸時間,通過傳輸的時間換算成距離。 電磁波傳輸速率和光速一樣,速度是299792.458km/s,可參見百度百科。如果想通過測試這個傳播時間換算距離,那麼就需要非常高的內部時鐘。然。。。並不是有了高速的內部時鐘即
NAT-T技術原理簡單分析及應用實驗解析
1.首先我們就IPSEC VPN的部署場景來做簡要分析: 場景1:如圖所示,企業的總部與分支機構分別架設了VPN裝置,分支機構的需求是同步企業內部的業務資料(屬企業內部的機密資訊),那麼就必須確保資料在公網上是安全包密傳遞的。這種情況下我們可以直接用IPSEC
Android ListView工作原理完全解析,帶你從原始碼的角度徹底理解
在Android所有常用的原生控制元件當中,用法最複雜的應該就是ListView了,它專門用於處理那種內容元素很多,手機螢幕無法展示出所有內容的情況。ListView可以使用列表的形式來展示內容,超出螢幕部分的內容只需要通過手指滑動就可以移動到螢幕內了。另外ListView還
Java 內部類實現原理簡單分析
轉載:原文地址http://www.fzhen.info/?p=300 本文重點不在與內部類的語法及使用,而是試圖解釋一些背後的原理。 內部類簡介 Java支援在類內部定義類,即為內部類。 普通內部類 把類的定義放在類的內部,例如: 程式碼清單1: public class Outer{ priv
android開機啟動流程簡單分析
android啟動 當載入程式啟動Linux核心後,會載入各種驅動和資料結構,當有了驅動以後,開始啟動Android系統同時會載入使用者級別的第一個程序init(system\core\init\init.cpp)程式碼如下: int main(int ar
JAVA程式碼覆蓋率工具JaCoCo-原理簡單分析
作為一個測試人員,保證產品的軟體質量是其工作首要目標,為了這個目標,測試人員常常會通過很多手段或工具來加以保證,覆蓋率就是其中一環比較重要的環節。 我們通常會將測試覆蓋率分為兩個部分,即“需求覆蓋率”和“程式碼覆蓋率”。 需求覆蓋:指的是測試人員對需求的瞭解程度,根據
JVM原理簡單分析
在Java語言裡堆(heap)和棧(stack)裡的區別 1. 棧(stack)與堆(heap)都是Java用來在Ram中存放資料的地方。與C++不同,Java自動管理棧和堆,程式設計師不能直接地設定棧或堆。 2. 棧的優勢是,存取速度比堆要快,僅次於直接位於CPU中的暫存器。但缺點是,存在棧中的資料大小
Spring原理簡單分析
本文知識點主要來自Spring技術內幕:深入解析Spring架構與設計原理(第2版) 。 1.spring設計理念 作業系統關心的是對儲存、計算、通訊、外圍裝置等物理資源的管理,為使用者提供一個統一的服務介面。 而spring其關心的是一些企業應用資源的使用,比如資料的持久
Android Animation動畫原理原始碼分析
Android 平臺提供了三類動畫,一類是 Tween 動畫-Animation,即通過對場景裡的物件不斷做影象變換 ( 平移、縮放、旋轉 ) 產生動畫效果;第二類是 Frame 動畫,即順序播放事先做好的影象,跟電影類似。最後一種就是3.0之後才出現的屬性動畫
Dubbo原理簡單分析
明顯,zookeeper可以被用作一個約會機制,讓參入的程序不在了解其他程序的(或網路)的情況下能夠彼此發現並進行互動,參入的各方甚至不必同時存在,只要在zookeeper留下一條訊息,在該程序結束後,另外一個程序還可以讀取這條資訊,從而解耦了各個節點之間的關係。 zook
AbstractRoutingDataSource 實現動態資料來源切換原理簡單分析
# AbstractRoutingDataSource 實現動態資料來源切換原理簡單分析 > 寫在前面,專案中用到了動態資料來源切換,記錄一下其執行機制。 ## 程式碼展示 下面列出一些關鍵程式碼,後續分析會用到 1. 資料配置 ```java @Configuration @PropertySou
mr原理簡單分析
背景 又是一個週末一天一天的過的好快,今天的任務幹啥呢,索引總結一些mr吧,因為前兩天有面試問過我?我當時也是簡單說了一下,畢竟現在寫mr程式的應該很少很少了,廢話不說了,結合官網和自己理解寫起。 官網 https://hadoop.apache.org/
Android ListView動畫特效實現原理及源代碼
stat 每一個 應該 所有 ner haar .get tde pri Android 動畫分三種,當中屬性動畫為我們最經常使用動畫,且能滿足項目中開發差點兒所有需求,google官方包支持3.0+。我們能夠引用三方包nineoldandr
木馬APP的簡單分析(Android Killer分析)
com smtp pow super text lsm integer ref rar 本文作者:三星s7edge 一.此貼目的:分析一個木馬APP樣本的行為。—————————————————————————————————————————————————-二.分析步驟及
Android查缺補漏(線程篇)-- AsyncTask的使用及原理詳細分析
catch 返回 rri 理解 ams tee ive lean keyword 本文作者:CodingBlock 文章鏈接:http://www.cnblogs.com/codingblock/p/8515304.html 一、AsyncTask的使用 AsyncT
Android XListView實現原理講解及分析
就是 指定 不同 true -h -name 修改 一個 部分 XListview是一個非常受歡迎的下拉刷新控件,但是已經停止維護了。之前寫過一篇XListview的使用介紹,用起來非常簡單,這兩天放假無聊,研究了下XListview的實現原理,學到了很多,今天分享給大家。
Android ListView分析
一.概述 在android開發中ListView是比較常用的元件,它以列表的形式展示具體內容,並且能夠根據資料的長度自適應顯示。本文將著重介紹一個使用BaseAdatper介面卡將資料庫中的資料顯示到介面的小案例。 二.列表的顯示需要三個元素: 1.ListVeiw 用來展示
網口掃盲二:Mac與Phy組成原理的簡單分析(轉)
1. general 下圖是網口結構簡圖.網口由CPU、MAC和PHY三部分組成.DMA控制器通常屬於CPU的一部分,用虛線放在這裡是為了表示DMA控制器可能會參與到網口資料傳輸中. &