Android優化之SparseArray替代HashMap打賞

Java開發過程中,一般免不了使用HashMap來存儲鍵值對以方便各種需求的實現,但是對于Android這種對內存非常敏感的移動平臺,很多時候使用一些Java的API并不能達到更好的性能,相反反而更消耗內存,所以針對Android這種移動平臺,也推出了更符合自己的API,比如SparseArray、ArrayMap用來代替HashMap在有些情況下能帶來更好的性能提升。

對于SparseArray,比HashMap更省內存,在某些條件下性能更好,主要是因為它避免了對key的自動裝箱(int轉為Integer類型等),它內部則是通過兩個數組來進行數據存儲的,一個存儲key,另外一個存儲value,為了優化性能,它內部對數據還采取了壓縮的方式來表示稀疏數組的數據,同時,還實現了SparseIntArray、SparseLongArray、SparseBooleanArray。使用上,幾乎和HashMap的API無異,這里僅以SparseArray為例:

常用API

添加數據

public void put(int key, E value)

刪除數據

public void remove(int key)

或者

public void delete(int key)

這里remove只是delete的一個alias,沒任何差異。注意:僅SparseArray實現了remove,其余幾個實現則只有delete,可能SparseArray只是為了保持與Map的API相似吧。

獲取數據

public E get(int key)

或者

public E get(int key, E valueIfKeyNotFound)

顧名思義,后者是查詢不到時的返回值。注意:這里面SparseArray使用get的時候查找不到時返回為null,而SparseIntArray、SparseLongArray則默認返回0,SparseBooleanArray默認返回false。

特有方法

獲取對應的key:

public int keyAt(int index)

獲取對應的value:

public E valueAt(int index)

獲取對應的key所在位置索引,由于采用二分法查找鍵的位置,所以沒有的話返回小于0的數值,而不是返回-1。注意:返回的負數其實是表示它在哪個位置就找不到了,如果你存了5個,查找的鍵大于5個值的話,返回就是-6

public int indexOfKey(int key)

獲取對應的value所在位置索引,不存在則返回-1

public int indexOfValue(E value)

應用場景

雖說SparseArray性能比較好,但是由于其添加、查找、刪除數據都需要先進行一次二分查找,所以在數據量大的情況下性能并不明顯,將降低至少50%。

滿足下面兩個條件我們可以使用SparseArray代替HashMap:

1、數據量不大,最好在千級以內

2、key必須為Integer類型

如果key為非Integer且數據量在千級以下,可以選擇ArrayMap替代HashMap,這里不再,內部實現和SparseArray類似并存儲了Hash值,這里不再介紹。

回顧總結

博主最近就是被SparseIntArray坑了一把,女票公司最近給她接一個app的維護,貌似是前人聽了android studio的建議,把HashMap換成了SparseIntArray,存儲的是整型的鍵和值,因為存儲的是ListView的索引,值為ListView的狀態,展開或折疊,展開存1折疊存0,而這貨又不看代碼,判斷SparseIntArray是否有特定key的時候,使用了keyAt來判斷,事實上這個非常容易引起數組越界,而SparseIntArray又默認初始化10個長度,再加上早期app數據不超過10個,后面數據超過10之后,就爆出問題了。這個問題給我看,我第一想法是,既然越界,就判斷唄,然后就判斷了傳入key是否超過數組長度,看似沒問題,一天后又測出,ListView狀態不能切換,這才仔細閱讀了一下源碼,發現這里實際上該使用indexOfKey,判斷小于0的則為不存在,大于0則為存在,又或者,這里面實際根本不用判斷,因為SparseIntArray找不到對應key的情況返回的就是我們需要返回的0,所以,我們每次indexOfKey(內部和get一樣,都會先查詢)去查找一次,反而是浪費了時間。這里不得不吐槽下這個代碼的作者,如果對于不熟悉的API沒有透析,還是不要亂用得好,免得誤導后面接手的哈。

補充一點,如果是使用SparseArray替代HashMap,其實是可以完全按照HashMap的使用方式來使用的,因為SparseArray的get方法找不到的時候默認返回null,這個不像SparseIntArray等實現,返回值一般和我們正常需求值沒有太大異議,我們完全可以通過判斷get得到的值是否為null來判斷key是否存在,換句話說,我們簡單替換HashMap為SparseArray時,只需替換聲明即可,后面API可以完全覆蓋。

簡單總結一下,方便新人。

Android優化之SparseArray替代HashMap
文章《Android優化之SparseArray替代HashMap》二維碼
  • 微信打賞
  • 支付寶打賞

已有1條評論

  1. 游客 43

    感覺不錯哦,認真拜讀咯!

    2017-03-26 12:06 回復

(必填)

(必填)

(可選)

黑龙江22选5开奖