源码分析
首先来看构造函数:
public SparseArray() {
this(10);
}
public SparseArray(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = EmptyArray.INT;
mValues = EmptyArray.OBJECT;
} else {
mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
mKeys = new int[mValues.length];
}
mSize = 0;
}
这有两个构造函数,明显从第一个知道,默认的初始容量为10,接着第二个构造函数,那么我们来看EmptyArray:
//Google搜
public final class EmptyArray {
private EmptyArray() {}
public static final boolean[] BOOLEAN = new boolean[0];
public static final byte[] BYTE = new byte[0];
public static final char[] CHAR = new char[0];
public static final double[] DOUBLE = new double[0];
public static final int[] INT = new int[0];
public static final Class<?>[] CLASS = new Class[0];
public static final Object[] OBJECT = new Object[0];
public static final String[] STRING = new String[0];
public static final Throwable[] THROWABLE = new Throwable[0];
public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];
}
接着ArrayUtils.newUnpaddedObjectArray用于创建优化后的数组,该方法实际上是一个Native方法,它解决了当数组中的元素没有填满时造成的空间浪费(知道这点就行吧,我也不清楚原因)
https://blog.youkuaiyun.com/easyer2012/article/details/37871031
接下来来看看put方法:
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
i = ~i;
if (i < mSize && mValues[i] == DELETED) {
mKeys[i] = key;
mValues[i] = value;
return;
}
if (mGarbage && mSize >= mKeys.length) {
gc();
// Search again because indices may have changed.
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
先看看ContainerHelpers.binarySearch:
// This is Arrays.binarySearch(), but doesn't do any argument validation.
static int binarySearch(int[] array, int size, int value) {
int lo = 0;
int hi = size - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final int midVal = array[mid];
if (midVal < value) {
lo = mid + 1;
} else if (midVal > value) {
hi = mid - 1;
} else {
return mid; // value found
}
}
return ~lo; // value not present
}
一看到这个循环,就知道时采用的是二分法查找,这样间接的知道了,key这个数组也是按照大小排列好了的,如果没找到返回的是~lo,这个方法中,我们明确的知道lo一定会为回负数,返回的是~lo,也就是负数,这就标志了现在的key数组里面是没有put进来的key的,同时lo已经确定好了在key数组里面的位置,接下来有个判断mValues[i] == DELETED,这是怎么回事呢,按照前面的理解,返回的是负数,说明是数组里面没有,可以直接的加入put进来的就行了,多出来这个步骤有什么用,那主要的是DELETED这个标志,通过查找,我们可以发现,在delete相关的方法中出现了:
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
mValues[i] = DELETED;
mGarbage = true;
}
}
}
只列出这一个,其他的也差不多意思,从这里可以看出来,删除的只是value,key是没有被删除的,这样就很好理解上面那个判断了
接着下面一个判断,通过全局查找,mGarbage意思就是执行过相关的delete方法,mGarbage会被赋值true,看看gc方法吧
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
int n = mSize;
int o = 0;
int[] keys = mKeys;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
Object val = values[i];
if (val != DELETED) {
if (i != o) {
keys[o] = keys[i];
values[o] = val;
values[i] = null;
}
o++;
}
}
mGarbage = false;
mSize = o;
// Log.e("SparseArray", "gc end with " + mSize);
}
这个方法大概意思就是把删掉的清除掉,重新排列当前的两个数组,把标记为DELETED除去,经过这gc操作,数组大小发生了改变,也就是put说要重新的找出应该放入的位置
接着就是把put的放入到数组当中GrowingArrayUtils.insert:
public static <T> T[] insert(T[] array, int currentSize, int index, T element) {
assert currentSize <= array.length;
if (currentSize + 1 <= array.length) {
System.arraycopy(array, index, array, index + 1, currentSize - index);
array[index] = element;
return array;
}
@SuppressWarnings("unchecked")
T[] newArray = ArrayUtils.newUnpaddedArray((Class<T>)array.getClass().getComponentType(),
growSize(currentSize));
System.arraycopy(array, 0, newArray, 0, index);
newArray[index] = element;
System.arraycopy(array, index, newArray, index + 1, array.length - index);
return newArray;
}
如果当前的数组还没有满,则在当前的数组里面增加,否则新建一个数组,把当前的数组里面的元素放入新数组,新数组长度为growSize(currentSize):
public static int growSize(int currentSize) {
return currentSize <= 4 ? 8 : currentSize * 2;
}
也就是增大两倍,最小为8
接着来看看get方法
public E get(int key) {
return get(key, null);
}
public E get(int key, E valueIfKeyNotFound) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i < 0 || mValues[i] == DELETED) {
return valueIfKeyNotFound;
} else {
return (E) mValues[i];
}
}
非常容易懂把,那就不分析了,总的来说,分析完put,其他的都好理解了
2总结:
SparseArray是android里为