分析源码之前先来介绍一下ArrayMap的存储结构,ArrayMap数据的存储不同于HashMap和SparseArray。
Java提供了HashMap,但是HashMap对于手机端而言,对空间的利用太大,所以Android提供了SparseArray和ArrayMap。二者都是基于二分查找,所以数据量大的时候,最坏效率会比HashMap慢很多。因此建议数量在千以内比较合适。
一、SparseArray
SparseArray对应的key只能是int类型,它不会对key进行装箱操作。它使用了两个数组,一个保存key,一个保存value。
SparseArray使用二分查找来找到key对应的插入位置。所以要保证mKeys数组有序。
remove的时候不会立刻重新清理删除掉的数据,而是将对一个的数据标记为DELETE(一个Object对象)。在必要的环节调用gc清理标记为DELETE的空间。
二、ArrayMap
重点介绍一下ArrayMap。
首先从ArrayMap的四个数组说起。mHashes,用于保存key对应的hashCode;mArray,用于保存键值对(key,value),其结构为[key1,value1,key2,value2,key3,value3,......];mBaseCache,缓存,如果ArrayMap的数据量从4,增加到8,用该数组保存之前使用的mHashes和mArray,这样如果数据量再变回4的时候,可以再次使用之前的数组,不需要再次申请空间,这样节省了一定的时间;mTwiceBaseCache,与mBaseCache对应,不过触发的条件是数据量从8增长到12。
上面提到的数据量有8增长到12,为什么不是16?这也算是ArrayMap的一个优化的点,它不是每次增长1倍,而是使用了如下方法(mSize+(mSize>>1)),即每次增加1/2。
有了上面的说明,读懂代码就容易多了。
1、很多地方用到的indexOf
这里使用了二分查找来查找对应的indexint indexOf(Object key, int hash) { final int N = mSize; // Important fast case: if nothing is in here, nothing to look for. //数组为空,直接返回 if (N == 0) { return ~0; } //二分查找,不细说了 int index = ContainerHelpers.binarySearch(mHashes, N, hash); // If the hash code wasn't found, then we have no entry for this key. //没找到hashCode,返回index,一个负数 if (index < 0) { return index; } // If the key at the returned index matches, that's what we want. //对比key值,相同则返回index if (key.equals(mArray[index<<1])) { return index; } // Search for a matching key after the index. //如果返回的index对应的key值,与传入的ke