特性
- Android 4.4之后提供的数据结构类型,为了兼容Android低版本同时提供了SparseArrayCompat,实际是一个东西。
- 只支持使用int - Object的方式存储数据,使用数组结构存储数据。
- 通过二分查找法优化了查找效率,相比HashMap最高提高50%的效率。
- 不适合存储大量数据,因为要使用二分查找法所有数组中元素已排序,在数据量大时插入和移除元素效率较低,适合存储几百个元素的场景。
- 优化缓存机制,移除元素时并不立即删除数组中的数据,而是将元素标记为删除,如果有元素插入时可以直接复用。只有触发自定义的gc时,被删除元素的存储空间才会被回收。
- 所以在存储Integer-Object形式的数据时,且数量量不太,有频繁的插入删除操作,使用SparseArray可以有效的提高效率。尤其适用于:ViewID - View的缓存场景。
源码分析
使用数组结构存储数据
private int[] mKeys;
private Object[] mValues;
//实际存储元素数量
private int mSize;
/**
* 数组大小默认为10
*/
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;
}
使用二分查找法来优化查找效率
/**
* 查找元素
*/
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];
}
}
删除元素
/**
* 删除元素
*/
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
//删除元素并没有立即移除对应的数据使数组紧致,
//而是将数组中对应位置的元素标记为DELETED
mValues[i] = DELETED;
mGarbage = true;
}
}
}
/**
* 真正的删除 gc
*/
private void gc() {
int n = mSize;
int o = 0;
int[] keys = mKeys;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
Object val = values[i];
//移除被标记为DELETED的元素,使数组紧致
if (val != DELETED) {
if (i != o) {
keys[o] = keys[i];
values[o] = val;
values[i] = null;
}
o++;
}
}
mGarbage = false;
mSize = o;
}