SparseArray,SparseBooleanArray和SparseIntArray

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

相關文章
相關標籤/搜索