安卓效能最佳化—使用ArrayMap與SparseArray
效能最佳化是我們做開發的必須要熟練掌握的技能,所以我打算寫一個效能最佳化專題,把平時用到的一些最佳化方法記錄下來,以便忘記的時候可以快速查詢,同時也給給其他開發者提供微薄之力吧:這篇文章講述的是在一些**特定的場景**使用使用ArrayMap與SparseArray代替HashMap,提高對資料的操作;先看看官方文件的描述:
ArrayMap is a generic key->value mapping data structure that is designed to be more memory efficient than a traditional HashMap, this implementation is a version of the platform's ArrayMap that can be used on older versions of the platform.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.Note that for containers holding up to hundreds of items, the performance difference is not significant, less than 50%.
從官方文件可以看出使用ArrayMap與SparseArray都要比傳統的HashMap 更有效率;但是最後有一個note,也就是當資料量達到千級以上的時候,ArrayMap與SparseArray都要比傳統的HashMap 效率更低50%;
HashMap
HashMap允許使用 null 值和 null 鍵,是基於hashing原理,我們透過put()和get()方法儲存和獲取物件。HashMap的結構:
HashMap結構
HashMap 有兩個引數影響其效能:初始容量 和載入因子。容量是雜湊表中桶的數量(預設16組),初始容量只是雜湊表在建立時的容量。載入因子 是雜湊表在其容量自動增加之前可以達到多滿的一種尺度。當雜湊表中的條目數超出了載入因子與當前容量的乘積時,則要對該雜湊表進行 rehash 操作(即重建內部資料結構),從而雜湊表將具有大約兩倍的桶數。載入因子預設值為0.75 。當我們將鍵值對傳遞給put()方法時,它呼叫鍵物件的hashCode()方法來計算hashcode,讓後找到bucket位置來儲存值物件。當獲取物件時,透過鍵物件的equals()方法找到正確的鍵值對,然後返回值物件。HashMap使用LinkedList來解決碰撞問題,當發生碰撞了,物件將會儲存在LinkedList的下一個節點中。 HashMap在每個LinkedList節點中儲存鍵值對物件。
put()方法
當兩個Key同時hash到一個值時,就會出現這樣的衝突。這個衝突主要有2種解決方法。
1、開放地址,亦即如果hash衝突,則在空閒的位置進行插入
2、hash複用,同一個hash值,鏈式地加入多個value
get()方法
HashMap還有很多方法,這裡就不一一例舉了;
透過get與put的原始碼,可以看出HashMap獲取資料是透過遍歷Entry[]陣列來得到對應的元素,在資料量很大時候會比較慢,所以在Android中,HashMap是比較費記憶體的,我們在一些情況下可以使用SparseArray和ArrayMap來代替HashMap。
SparseArray
可以看出SparseArray由兩個陣列mKeys和mValues存放;其中key的型別為int型,這就顯得SparseArray比HashMap更省記憶體一些,SparseArray在儲存和讀取資料時候,使用的是二分查詢法,那何為二分法呢?
先看一下put()方法:
在上面程式碼中有一個ContainerHelpers.binarySearch(mKeys, mSize, key)方法,這是Arrays提供了一個方便查詢的方法,也就是我們所說的“二分法”;
get()方法:
使用二分查詢法和之前的key比較當前我們新增的元素的key的大小,然後按照從小到大的順序排列好,所以,SparseArray儲存的元素都是按元素的key值從小到大排列好的。而在獲取資料的時候,也是使用二分查詢法判斷元素的位置,所以,在獲取資料的時候非常快,比HashMap快的多,因為HashMap獲取資料是透過遍歷Entry[]陣列來得到對應的元素。
其他的一些方法:
ArrayMap
ArrayMap是一個鍵值對對映的資料結構,它設計上更多的是考慮記憶體的最佳化,內部是使用兩個陣列進行資料儲存,一個陣列記錄key的hash值,另外一個陣列記錄Value值,它和SparseArray一樣,也會對key使用二分法進行從小到大排序,區別是ArrayMap的key是hash值,
可以看出ArrayMap的構造方法直接呼叫的父類的構造方法:
put()方法:
get()方法與SparseArray的一樣,就不哆嗦了:
總結
因為ArrayMap與SparseArray內部都使用了二分法進行從小到大的排序,所以當資料量很大的時候,效率至少降低一半,所以谷歌推薦資料量在千級以內時使用ArrayMap與SparseArray,資料量非常大時使用HashMap;
作者:lin_林
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2809898/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料結構HashMap(Android SparseArray 和ArrayMap)資料結構HashMapAndroid
- 更適合Android的集合 SparseArray/ArrayMap/ArraySetAndroid
- babel-polyfill使用與效能最佳化Babel
- 記憶體洩漏與排查流程——安卓效能優化記憶體安卓優化
- 安卓EasyLib的使用安卓
- RecyclerView 效能優化 | 安卓 offer 收割基View優化安卓
- SparseArray分析
- 安卓Toolbar使用 Demo(Kotlin)安卓Kotlin
- 安卓程式碼、圖片和佈局最佳化安卓
- 安卓註解使用介紹安卓
- SparseArray原理分析
- 安卓應用優化:使用反射測試安卓裝置是否使用“動態桌布”安卓優化反射
- 安卓驅動、HAL、JNI與java安卓Java
- 安卓使用物理鍵監聽器安卓
- 使用fiddler和安卓模擬器抓取安卓客戶端資料包安卓客戶端
- 安卓安卓
- 效能最佳化指南:效能最佳化的一般性原則與方法
- SparseArray 原始碼解析原始碼
- 群控與安卓底層開發安卓
- ArrayMap是如何提高記憶體的使用效率的?記憶體
- 使用Exp和Expdp匯出資料的效能對比與最佳化
- 利用 Page Visibility API 最佳化網頁效能與使用者體驗API網頁
- 最新2018年6月安卓手機安兔兔效能排行榜安卓
- 前端效能最佳化實踐方向與方法前端
- redis georadius原始碼分析與效能最佳化Redis原始碼
- Apache安裝與最佳化教程。Apache
- 安卓應用效能除錯和優化經驗分享安卓除錯優化
- Mac 安卓Studio使用外部模擬器Mac安卓
- 安卓EventBus使用方法,eventbus舉例安卓
- 在安卓上使用OpenCV的指南 - kdnuggets安卓OpenCV
- 看雪安卓研修班,安卓逆向安卓
- 安兔兔:2024年5月安卓旗艦手機效能排行榜安卓
- h5與安卓和ios除錯H5安卓iOS除錯
- 安卓案例:聯選系部與專業安卓
- 前端效能最佳化之-使用depcheck檢查專案中未被使用的依賴並解除安裝前端
- 前端效能最佳化---防抖與節流--02前端
- 安卓Android虛擬機器分享及使用安卓Android虛擬機
- 在 pc 端使用安卓截圖軟體安卓