Android容器类小结

系列文章地址:
Android容器类-ArraySet原理解析(一)
Android容器类-ArrayMap原理解析(二)
Android容器类-SparseArray原理解析(三)
Android容器类-SparseIntArray原理解析(四)android

相较于其余设备,移动设备有本身的特色,内存小是一个很突出的问题,Google针对android设备的这一特色,开发了一套容器框架,目的就是为了更加高效地利用内存。接下来就对这些容器进行一下总结。api

组织结构

image
以上是android中容器的实现继承结构,简单梳理一下:

  • ArraySet实现了SetCollections接口,在api 23中添加
  • ArrayMap实现了Map接口,在api 19中添加
  • SparseArraySparseIntArraySparseBooleanArray实现了Cloneable接口,在api 1中添加
  • SparseLong实现了Cloneable接口,在api 18中添加

分类

从**功能**上划分,能够将以上容器划分为两类:数组

  • 存储元素
    ArraySet优化了HashSet对元素的存储
    缓存

  • 存储键值对 相较于HashMap,具体的优化方向以下:
    ArrayMap优化了HashMap存储Object --> Object的键值存储;
    SparseArray优化了int --> Object的键值存储;
    SparseIntArray优化了int --> int的键值存储;
    SparseBooleanArray优化了 int --> boolean的键值存储;
    SparseLongArray优化了 int --> long的键值存储。
    微信

优化方法

从组织结构能够看出,能够将这些容器分为3类:ArraySet,ArrayMap和剩余的容器。经过前面的分析能够知道,ArraySetArrayMap使用的相同的优化方式,SparseArray在进行优化的时候使用gc垃圾回收策略,故从优化方法上进行分类的话能够分一下三类:数据结构

  • ArraySet, ArrayMap 使用数组mKeys存储key的hash值,hash值在mKeys的位置为index,并将value存储到mValues数组对应下标的位置(ArrayMapkeyvalue分别在mValuesindex * 2index * 2 + 1的位置)。查找或者修改元素时,使用二分查找在mKeys中找到元素在mValues的下标,而后进行修改或者返回。
  • SparseArray 使用int类型的mKeys数组存储int类型的键,下标为index,将Object类型的value存储在在Object类型的数组mValuesindex位置,在查找和修改时,使用二分查找在mKeys中找到元素在mValues的下标,而后进行修改或者返回。在删除value时,SparseArray并不直接进行数组元素的移动,而是将待删除的value标记为DELETED状态,在gc的过程当中将全部非DELETED状态的元素移动到数组的最前面,从而减小二分查找的时间。
  • SparseIntArray, SparseLongArray, SparseBooleanArray 这3个容器能够理解成专用容器,使用int类型数组和对应类型的数组;使用二分查找快速查找元素,而后进行删除,修改,添加操做。

优化共同点与差别

虽然这些容器存储的元素类型不一样,可是经过分析能够发现他们在内存优化中的共同点,接下来就分析下这些容器在优化上存在的共同点和差别。框架

共同点性能

  • 数据结构 优化

    image
    这里的数据结构是指容器的底层存储结构,虽然在ArrayMap中mValues的长度是mKeys的2倍,但也仅仅是数组长度上的差别,底层存储使用的思想仍然是同样的;int类型的数组mKeys里的元素时按照升序进行排列的。相较于HashMap使用Node结构存储,这样的存储方式使用更小的存储空间存储k-v,同时避免了原始数据类型的自动装箱。

  • 查找方法 在组织结构中列出的容器,他们在进行元素查找时,都会先在mKeys数组中利用二分查找找到元素的下标index,而后使用indexmValues数组中对value进行操做。.net

  • 获取带插入下标 在进行元素插入时,会首先使用二分查找在mKeys数组中查找元素的下标,若是元素不存在,则二分查找会返回元素待插入位置的取反。

不一样点

  • key的处理 ArraySet, ArrayMap底层实现时,会计算待插入元素的hash值,根据hash值,在mKeys找到待插入位置;SparseArraySparseXXXArray存储的时候直接使用key值,不会进行hash计算。
  • null的处理 ArraySetArrayMap容许插入keynull的元素,key的hash值为0;SparseArraySparseXXXArray存储的时因为直接使用int类型的数据做为key,故不存在keynull的状况。
  • 缓存 为了不频繁的内存回收,ArraySetArrayMap添加了缓存结构,SparseArraySparseXXXArray没有缓存
  • 扩容规则 ArraySetArrayMap在进行扩容的时,容量的变化规则为4, 8 , size * 2 / 3SparseArraySparseXXXArray使用ArrayUtils.newUnpaddedArray创建新的数据,将原来的数据拷贝到新数组中。

使用建议

虽然这些容器在Android设备上能够更高效地利用内存,可是仍是存在使用使用限制。

  • 兼容性 在组织结构中,能够看到,并非全部的容器都是从api 1就开始提供的,在使用具体的容器时,须要考虑应用的兼容。
  • 对性能的影响 虽然ArrayMap在删除时不直接使用移动元素的方式删除元素,可是在获取数组元素等操做中仍是
  • 对数量的限制 在对元素进行查找时会使用二分查找,元素数量较大(超过1000)时,查找效率会下降,相较于HashMap只要数量不超过1000,效率最多不会降低50%。

总结

前面说了不少,其实android容器优化的根本思想就是使用int到其余类型的映射,使用数组保存着两个映射,用以优化HashMapk-v的存储。这种优化适用于元素数量较少(少于1000)的状况。

关注微信公众号,最新技术干货实时推送

image
相关文章
相关标签/搜索