在 Android 开发中,SparseArray
是一个高效的数据结构,用于替代 HashMap
存储少量键值对。与传统的 HashMap
相比,它能更好地减少内存开销。本文将从源码解析到实际应用,带你深入了解 SparseArray
。
SparseArray 简介
SparseArray
是 Android 提供的一个工具类,位于 android.util
包下,用于存储 int
类型的键和 Object
类型的值。其核心特点是:
- 高效:避免了
HashMap
使用的装箱(Boxing)操作。 - 内存友好:在数据量较少时,比
HashMap
更节省内存。
以下是一个基本用法示例:
SparseArray<String> sparseArray = new SparseArray<>();
sparseArray.put(1, "Value1");
sparseArray.put(2, "Value2");
String value = sparseArray.get(1); // 返回 "Value1"
SparseArray 与 HashMap 对比
特性 | SparseArray | HashMap |
---|---|---|
键的类型 | int | 任意对象 |
值的类型 | 任意对象 | 任意对象 |
内存使用效率 | 高(少量数据) | 一般 |
适用场景 | 少量键值对的存储 | 大量键值对的存储 |
线程安全 | 否 | 否 |
SparseArray 源码解析
内部数据结构
SparseArray
的内部使用两个数组实现:
int[] keys
:存储键的数组,按升序排列。Object[] values
:存储值的数组,与keys
一一对应。
核心方法解析
put()
put(int key, E value)
方法用于插入键值对。其实现分为以下几个步骤:
- 通过二分查找在
keys
中定位键的位置。 - 如果键已存在,则更新对应的值;否则,插入新键值对。
以下是部分源码:
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(keys, size, key);
if (i >= 0) {
values[i] = value; // 更新已有键的值
} else {
i = ~i; // 计算插入位置
keys = insertKey(keys, size, i, key);
values = insertValue(values, size, i, value);
size++;
}
}
get()
get(int key)
方法通过二分查找快速定位键的位置,然后返回对应的值。
源码如下:
public E get(int key) {
int i = ContainerHelpers.binarySearch(keys, size, key);
if (i >= 0) {
return (E) values[i];
} else {
return null;
}
}
remove()
remove(int key)
方法删除指定键值对。
主要步骤:
- 找到键的位置。
- 移动数组,填补被删除元素的空位。
public void remove(int key) {
int i = ContainerHelpers.binarySearch(keys, size, key);
if (i >= 0) {
System.arraycopy(keys, i + 1, keys, i, size - (i + 1));
System.arraycopy(values, i + 1, values, i, size - (i + 1));
size--;
}
}
SparseArray 的优势
通过以上源码可以看出,SparseArray
的优势主要体现在:
- 避免装箱:直接使用
int
作为键,减少了HashMap
中的装箱与拆箱操作。 - 内存友好:省去了
HashMap
的Entry
对象。 - 排序:内部键数组是有序的,便于快速查找。
劣势
- 在插入和删除操作中需要移动数组,性能不如
HashMap
。 - 适用于小数据量场景,大数据量时性能下降。
应用实战
以下通过一个实际场景展示 SparseArray
的使用。
示例:管理 RecyclerView 的视图类型
在使用 RecyclerView
时,通常需要处理多种视图类型。SparseArray
可以用来管理视图类型与对应的布局资源 ID。
实现代码
public class ViewTypeManager {
private SparseArray<Integer> viewTypeMap = new SparseArray<>();
public void addViewType(int viewType, int layoutResId) {
viewTypeMap.put(viewType, layoutResId);
}
public int getLayoutResId(int viewType) {
return viewTypeMap.get(viewType, -1);
}
}
// 使用示例
ViewTypeManager manager = new ViewTypeManager();
manager.addViewType(1, R.layout.item_type_1);
manager.addViewType(2, R.layout.item_type_2);
int layoutId = manager.getLayoutResId(1); // 返回 R.layout.item_type_1
效果图
以下展示了 RecyclerView
的运行效果:
总结
SparseArray
是 Android 开发中一个非常实用的工具类,尤其适用于少量键值对的存储。通过本文的源码解析和实际应用,相信你对 SparseArray
已经有了更深入的理解。在实际开发中,合理使用 SparseArray
,可以提升代码的性能和内存利用率。