package android.util; import com.android.internal.util.ArrayUtils; /** * SparseArrays 利用integer去管理object對象。不像一個正常的object對象數組,它能在索引數中快速的查找到所需的結果。(這 * 句話是音譯,原意是能在衆多索引數中「撕開一個缺口」,爲何原文這麼表達?下面會慢慢說清楚。)它比HashMap去經過Integer索引 * 查找object對象時在內存上更具效率,不只由於它避免了用來查找的自動「裝箱」的keys,而且它的數據結構不依賴額外的對象去 * 各個映射中查找匹配。 * * SparseArrays map integers to Objects. Unlike a normal array of Objects, * there can be gaps in the indices. It is intended to be more memory efficient * than using a HashMap to map Integers to Objects, both because it avoids * auto-boxing keys and its data structure doesn't rely on an extra entry object * for each mapping. * * 請注意,這個容器會保持它的映射關係在一個數組的數據結構中,經過二分檢索法驅查找key。(這裏咱們終於知道,爲什麼這個工具類中, * 提供的添加映射關係的操做中,key的類型必須是integer。由於二分檢索法,將從中間「切開」,integer的數據類型是實現這種檢索過程的保證。) * * 若是保存大量的數據,這種數據結構是不適合的,換言之,SparseArray這個工具類並不該該用於存儲大量的數據。這種狀況下,它的效率 * 一般比傳統的HashMap更低,由於它的查找方法而且增長和移除操做(任意一個操做)都須要在數組中插入和刪除(兩個步驟才能實現)。 * * 若是存儲的數據在幾百個之內,它們的性能差別並不明顯,低於50%。 * * (OK,那麼光看Android官方的介紹咱們就有初步結論了,大量的數據咱們相對SparseArray會優先選擇HashMap,若是數據在幾百個這個數目, * 那麼選擇它們任意一個去實現區別不大,若是數量較少,就選擇SparseArray去實現。 其實若是咱們理解了二分法,就很容易了SparseArray的 * 實現原理,以及SparseArray和HashMap它們之間的區別了。) * * <p>Note that this container keeps its mappings in an array data structure, * using a binary search to find keys. The implementation is not intended to be appropriate for * data structures * that may contain large numbers of items. It is generally slower than a traditional * HashMap, since lookups require a binary search and adds and removes require inserting * and deleting entries in the array. For containers holding up to hundreds of items, * the performance difference is not significant, less than 50%.</p> * * * 爲了提升性能,這個容器包含了一個實現最優的方法:當移除keys後爲了馬上使它的數組緊密,它會「遺留」已經被移除(標記了要刪除)的條目(entry) 。 * 所被標記的條目(entry)(還未被看成垃圾回收掉前)能夠被相同的key複用,也會在垃圾回收機制看成全部要回收的條目的一員被回收,從而使存儲的數組更緊密。 * * (咱們下面看源碼就會發現remove()方法實際上是調用delete()方法的。印證了上面這句話所說的這種優化方法。 * 由於這樣,能在每次移除元素後一直保持數組的數據結構是緊密不鬆散的。) * * 垃圾回收的機制會在這些狀況執行:數組須要擴充,或者映射表的大小被恢復,或者條目值被從新檢索後恢復的時候。 * * <p>To help with performance, the container includes an optimization when removing * keys: instead of compacting its array immediately, it leaves the removed entry marked * as deleted. The entry can then be re-used for the same key, or compacted later in * a single garbage collection step of all removed entries. This garbage collection will * need to be performed at any time the array needs to be grown or the the map size or * entry values are retrieved.</p> * * 當調用keyAt(int)去獲取某個位置的key的鍵的值,或者調用valueAt(int)去獲取某個位置的值時,多是經過迭代容器中的元素 * 去實現的。 * * <p>It is possible to iterate over the items in this container using * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using * <code>keyAt(int)</code> with ascending values of the index will return the * keys in ascending order, or the values corresponding to the keys in ascending * order in the case of <code>valueAt(int)<code>.</p> */ public class SparseArray<E> implements Cloneable { //... }
####Android開發中高效的數據結構 android開發中,在java2ee或者android中經常使用的數據結構有Map,List,Set,但android做爲移動平臺,有些api(不少都是效率問題)顯然不夠理想,本着造更好輪子的精神,android團隊編寫了本身的api用來代替java api 1、SimpleArrayMap<K,V>與ArrayMap<K,V> 實質上ArrayMap繼承自SimpleArrayMap,主要是爲了實現像HashMap同樣的api方法,讓習慣使用HashMap的開發者感受不到差別,本質上是SimpleArrayMap+Map的再封裝。 通常來講使用這2個類主要來代替HashMap,由於他們比HashMap更加高效,對內存也進行了優化。 2、SparseArray<T>與SparseArrayCompat<T>和LongSparseArray<T> 這3個類中,前2個基本上是同一類,只不過第二個類有removeAt方法,第三個是Long類型的。 這3個類也是用來代替HashMap,只不過他們的鍵(key)的類型是整型Integer或者Long類型,在實際開發中,如月份縮寫的映射,或者進行文件緩存映射,viewHolder都特別適用 3、AtomicFile AtomicFile首先不是用來代替File的,而是做爲File的輔助類從在, AtomicFile的做用是實現事務性原子操做,即文件讀寫必須完整,適合多線程中的文件讀寫操做。 用來實現多線程中的文件讀寫的安全操做 ---- #####用SparseArray代替HashMap SparseArray是android提供的一個工具類,它能夠用來替代hashmap進行對象的存儲,其內部實現了一個矩陣壓縮算法,很適合存儲稀疏矩陣的。 PS:support包中還提供了兼容的類SparseArrayCompat,基本和SparseArray是同一個類,只不過第二個類有removeAt方法 針對源碼的詳細分析:[http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/](http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/ "http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/") 1、和Hashmap的對比 既然android推薦用這個東西,天然有用它的道理。其內部實現了壓縮算法,能夠進行矩陣壓縮,大大減小了存儲空間,節約內存。此外它的查找算法是二分法,提升了查找的效率。 替換原則: 1> 若是用到了: HashMap<Integer, E> hashMap = new HashMap<Integer, E>(); 能夠替換爲:SparseArray<E> sparseArray = new SparseArray<E>(); 2> 若是用到了:HashMap<Integer, Boolean> hashMap = new HashMap<Integer, Boolean> 能夠替換爲:SparseBooleanArray array = new SparseBooleanArray(); 3> 若是用到了:HashMap<Integer, Integer> hashMap = new HashMap<Integer, Integer> 能夠替換爲:SparseIntArray array = new SparseIntArray(); 2、用法 既然是鍵值對那麼就有增刪改查,但要記得先初始化: Button btn = null; // 測試view,無心義 Button btn02 = null; // 測試view,表示新增的對象 final int KEY = 1; /* * SparseArray指的是稀疏數組(Sparse * array),所謂稀疏數組就是數組中大部分的內容值都未被使用(或都爲零),在數組中僅有少部分的空間使用 * 。所以形成內存空間的浪費,爲了節省內存空間,而且不影響數組中原有的內容值,咱們能夠採用一種壓縮的方式來表示稀疏數組的內容。 */ SparseArray<View> array = new SparseArray<View>(); 2.1 增長數據 /* 增長數據 */ //public void put(int key, E value) {} array.put(KEY, btn); //public void append(int key, E value){} array.append(KEY, btn); 2.2 修改數據 /* 修改數據 */ //在put數據以前,會先查找要put的數據是否已經存在,若是存在就是修改,不存在就添加。 //public void put(int key, E value) array.put(KEY, btn); //public void setValueAt(int index, E value) array.setValueAt(KEY, btn02); 2.3 查找數據 /* 查找數據 */ //public E get(int key) array.get(KEY); //public E get(int key, E valueIfKeyNotFound) //其中get(int key)也只是調用了 get(int key,E valueIfKeyNotFound),最後一個從傳參的變量名就能看出,傳入的是找不到的時候返回的值.get(int key)當找不到的時候,默認返回null。 array.get(KEY, btn); // 若是這個key找不到value,那麼就返回第二個參數。和default value同樣 2.4 經過位置,查找鍵的值 // 查看第幾個位置的鍵: //public int keyAt(int index) array.keyAt(1); // 若是找不到就返回-1 2.5 經過位置,查找值 // 查看第幾個位置的值: //public E valueAt(int index) array.valueAt(1); // 查看值所在位置,沒有的話返回-1: //public int indexOfValue(E value) array.indexOfValue(btn); 3、測試代碼 package com.kale.pictest; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.View; import android.widget.Button; /** * @author: * @description : * @web : http://stormzhang.com/android/2013/08/01/android-use-sparsearray-for-performance-optimization/ * @date :2015年1月19日 */ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); Log.d("TAG", "Max memory is " + maxMemory + "KB"); Button btn = null; // 測試view,無心義 Button btn02 = null; // 測試view,表示新增的對象 final int KEY = 1; /* * SparseArray指的是稀疏數組(Sparse * array),所謂稀疏數組就是數組中大部分的內容值都未被使用(或都爲零),在數組中僅有少部分的空間使用 * 。所以形成內存空間的浪費,爲了節省內存空間,而且不影響數組中原有的內容值,咱們能夠採用一種壓縮的方式來表示稀疏數組的內容。 */ SparseArray<View> array = new SparseArray<View>(); /* 增長數據 */ //public void put(int key, E value) {} array.put(KEY, btn); //public void append(int key, E value){} array.append(KEY, btn); /* 修改數據 */ //在put數據以前,會先查找要put的數據是否已經存在,若是存在就是修改,不存在就添加。 //public void put(int key, E value) array.put(KEY, btn); //public void setValueAt(int index, E value) array.setValueAt(KEY, btn02); /* 查找數據 */ //public E get(int key) array.get(KEY); //public E get(int key, E valueIfKeyNotFound) //其中get(int key)也只是調用了 get(int key,E valueIfKeyNotFound),最後一個從傳參的變量名就能看出,傳入的是找不到的時候返回的值.get(int key)當找不到的時候,默認返回null。 array.get(KEY, btn); // 若是這個key找不到value,那麼就返回第二個參數。和default value同樣 // 查看第幾個位置的鍵: //public int keyAt(int index) array.keyAt(1); // 若是找不到就返回-1 // 查看第幾個位置的值: //public E valueAt(int index) array.valueAt(1); // 查看值所在位置,沒有的話返回-1: //public int indexOfValue(E value) array.indexOfValue(btn); SparseBooleanArray d; } } 測試代碼四: public class FragmentPagerItemAdapter extends FragmentPagerAdapter { private final FragmentPagerItems mPages; private final SparseArrayCompat<WeakReference<Fragment>> mHolder; public FragmentPagerItemAdapter(FragmentManager fm, FragmentPagerItems pages) { super(fm); mPages = pages; mHolder = new SparseArrayCompat<>(pages.size()); } @Override public int getCount() { return mPages.size(); } @Override public Fragment getItem(int position) { return getPagerItem(position).instantiate(mPages.getContext(), position); } @Override public Object instantiateItem(ViewGroup container, int position) { Object item = super.instantiateItem(container, position); if (item instanceof Fragment) { mHolder.put(position, new WeakReference<Fragment>((Fragment) item)); } return item; } @Override public void destroyItem(ViewGroup container, int position, Object object) { mHolder.remove(position); super.destroyItem(container, position, object); } @Override public CharSequence getPageTitle(int position) { return getPagerItem(position).getTitle(); } @Override public float getPageWidth(int position) { return super.getPageWidth(position); } public Fragment getPage(int position) { final WeakReference<Fragment> weakRefItem = mHolder.get(position); return (weakRefItem != null) ? weakRefItem.get() : null; } protected FragmentPagerItem getPagerItem(int position) { return mPages.get(position); } }
1,SparseArray的原理是二分檢索法,也所以key的類型都是整型。java
2,(HashMap和SparseArray比較)當存儲大量數據(起碼上千個)的時候,優先選擇HashMap。若是隻有幾百個,用哪一個區別不大。若是數量很少,優先選擇SparseArray。android
3,SparseArray有本身的垃圾回收機制。web