Android SparseArray 源码解析与应用实战

本文深入剖析了Android中的SparseArray数据结构,介绍了其原理及源码实现,并展示了如何在Android开发中应用这一高效的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在 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 对比

特性SparseArrayHashMap
键的类型int任意对象
值的类型任意对象任意对象
内存使用效率高(少量数据)一般
适用场景少量键值对的存储大量键值对的存储
线程安全

SparseArray 源码解析

内部数据结构

SparseArray 的内部使用两个数组实现:

  • int[] keys:存储键的数组,按升序排列。
  • Object[] values:存储值的数组,与 keys 一一对应。

核心方法解析

put()

put(int key, E value) 方法用于插入键值对。其实现分为以下几个步骤:

  1. 通过二分查找在 keys 中定位键的位置。
  2. 如果键已存在,则更新对应的值;否则,插入新键值对。

以下是部分源码:

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) 方法删除指定键值对。

主要步骤:

  1. 找到键的位置。
  2. 移动数组,填补被删除元素的空位。
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 的优势主要体现在:

  1. 避免装箱:直接使用 int 作为键,减少了 HashMap 中的装箱与拆箱操作。
  2. 内存友好:省去了 HashMapEntry 对象。
  3. 排序:内部键数组是有序的,便于快速查找。

劣势

  • 在插入和删除操作中需要移动数组,性能不如 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,可以提升代码的性能和内存利用率。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vincent(朱志强)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值