相信大家都明白,手机软件的开发不同于PC软件的开发,因为手机性能相对有限,内存也有限,所谓“寸土寸金”,可能稍有不慎,就会导致性能的明显降低。Android为了方便开发者,特意在android.util这个包中提供了几个提高效率的工具类,比如之前用过的LruCache类,这次我们来谈谈其他工具类,SparseArray,SparseBooleanArray和 SparseIntArray。

总体说,它们都是类似map这样key-value的存储方式,但是由于查找的算法不一样。因此效率也各不同。但要明白,没有说哪个一定是最好的。只有根据不同需求在不同场景去应用,才能获取较优的结果。下面我们来看看它们的“庐山真面目”吧。

SparseArray

本来想在这里好好介绍何为SparseArray。但看完源码和官方的文档,发现里面已经介绍的很仔细了。于是决定将源码中开始关于介绍SparseArray的那一段翻译在这里,最后总计几个要点。英文水平有限,翻译不恰当的地方请先见谅。

  1. package android.util;  
  2.   
  3. import com.android.internal.util.ArrayUtils;  
  4.   
  5. /** 
  6.  * SparseArrays 利用integer去管理object对象。不像一个正常的object对象数组,它能在索引数中快速的查找到所需的结果。(这 
  7.  * 句话是音译,原意是能在众多索引数中“撕开一个缺口”,为什么原文这么表达?下面会慢慢说清楚。)它比HashMap去通过Integer索引 
  8.  * 查找object对象时在内存上更具效率,不仅因为它避免了用来查找的自动“装箱”的keys,并且它的数据结构不依赖额外的对象去 
  9.  * 各个映射中查找匹配。 
  10.  *  
  11.  * SparseArrays map integers to Objects.  Unlike a normal array of Objects, 
  12.  * there can be gaps in the indices.  It is intended to be more memory efficient 
  13.  * than using a HashMap to map Integers to Objects, both because it avoids 
  14.  * auto-boxing keys and its data structure doesn't rely on an extra entry object 
  15.  * for each mapping. 
  16.  * 
  17.  * 请注意,这个容器会保持它的映射关系在一个数组的数据结构中,通过二分检索法驱查找key。(这里我们终于知道,为何这个工具类中, 
  18.  * 提供的添加映射关系的操作中,key的类型必须是integer。因为二分检索法,将从中间“切开”,integer的数据类型是实现这种检索过程的保证。) 
  19.  *  
  20.  * 如果保存大量的数据,这种数据结构是不适合的,换言之,SparseArray这个工具类并不应该用于存储大量的数据。这种情况下,它的效率 
  21.  * 通常比传统的HashMap更低,因为它的查找方法并且增加和移除操作(任意一个操作)都需要在数组中插入和删除(两个步骤才能实现)。 
  22.  *  
  23.  * 如果存储的数据在几百个以内,它们的性能差异并不明显,低于50%。 
  24.  *  
  25.  * (OK,那么光看Android官方的介绍我们就有初步结论了,大量的数据我们相对SparseArray会优先选择HashMap,如果数据在几百个这个数目, 
  26.  *  那么选择它们任意一个去实现区别不大,如果数量较少,就选择SparseArray去实现。 其实如果我们理解了二分法,就很容易了SparseArray的 
  27.  *  实现原理,以及SparseArray和HashMap它们之间的区别了。) 
  28.  *  
  29.  * <p>Note that this container keeps its mappings in an array data structure, 
  30.  * using a binary search to find keys.  The implementation is not intended to be appropriate for 
  31.  * data structures 
  32.  * that may contain large numbers of items.  It is generally slower than a traditional 
  33.  * HashMap, since lookups require a binary search and adds and removes require inserting 
  34.  * and deleting entries in the array.  For containers holding up to hundreds of items, 
  35.  * the performance difference is not significant, less than 50%.</p> 
  36.  * 
  37.  *   
  38.  * 为了提高性能,这个容器包含了一个实现最优的方法:当移除keys后为了立刻使它的数组紧密,它会“遗留”已经被移除(标记了要删除)的条目(entry) 。 
  39.  * 所被标记的条目(entry)(还未被当作垃圾回收掉前)可以被相同的key复用,也会在垃圾回收机制当作所有要回收的条目的一员被回收,从而使存储的数组更紧密。 
  40.  *  
  41.  * (我们下面看源码就会发现remove()方法其实是调用delete()方法的。印证了上面这句话所说的这种优化方法。 
  42.  * 因为这样,能在每次移除元素后一直保持数组的数据结构是紧密不松散的。) 
  43.  *  
  44.  * 垃圾回收的机制会在这些情况执行:数组需要扩充,或者映射表的大小被恢复,或者条目值被重新检索后恢复的时候。 
  45.  *   
  46.  * <p>To help with performance, the container includes an optimization when removing 
  47.  * keys: instead of compacting its array immediately, it leaves the removed entry marked 
  48.  * as deleted.  The entry can then be re-used for the same key, or compacted later in 
  49.  * a single garbage collection step of all removed entries.  This garbage collection will 
  50.  * need to be performed at any time the array needs to be grown or the the map size or 
  51.  * entry values are retrieved.</p> 
  52.  * 
  53.  * 当调用keyAt(int)去获取某个位置的key的键的值,或者调用valueAt(int)去获取某个位置的值时,可能是通过迭代容器中的元素 
  54.  * 去实现的。 
  55.  * 
  56.  * <p>It is possible to iterate over the items in this container using 
  57.  * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using 
  58.  * <code>keyAt(int)</code> with ascending values of the index will return the 
  59.  * keys in ascending order, or the values corresponding to the keys in ascending 
  60.  * order in the case of <code>valueAt(int)<code>.</p> 
  61.  */  
  62. public class SparseArray<E> implements Cloneable {  
  63.     //...  
  64. }  

至于完整的源码就不贴出来了,因为不多,大家可以自行看看。

这里总结下几个重要的点:

1,SparseArray的原理是二分检索法,也因此key的类型都是整型。

2,(HashMap和SparseArray比较)当存储大量数据(起码上千个)的时候,优先选择HashMap。如果只有几百个,用哪个区别不大。如果数量不多,优先选择SparseArray。

3,SparseArray有自己的垃圾回收机制。(当数量不是很多的时候,这个不必关心。)

接着将里面的主要方法列出来:

  1. private int index = 1;  
  2.     private String value = "value";  
  3.       
  4.     public void testSparseArray()  
  5.     {  
  6.         //创建一个SparseArray对象  
  7.         SparseArray<String> sparseArray = new SparseArray<String>();  
  8.           
  9.         //向sparseArray存入元素value,key为index  
  10.         sparseArray.put(index, value);  
  11.           
  12.         //这个方法本质也是利用put(key, value)去存入数据  
  13.         sparseArray.append(index, value);  
  14.           
  15.           
  16.         sparseArray.indexOfKey(index);  
  17.         //查找value所在的位置,如果不存在,则返回-1  
  18.         sparseArray.indexOfValue(value);  
  19.           
  20.           
  21.           
  22.         //更新某个key的值  
  23.         sparseArray.setValueAt(index, value);  
  24.           
  25.           
  26.           
  27.         //获取index所对应的值,没有则返回null  
  28.         sparseArray.get(index);  
  29.         //获取index所对应的值,没有则返回自定义的默认值"default-value"  
  30.         sparseArray.get(index,"default-value");  
  31.           
  32.           
  33.           
  34.         //删除index对应的元素  
  35.         sparseArray.delete(index);  
  36.         //移除,本质也是调用delete(int)方法  
  37.         sparseArray.remove(index);  
  38.           
  39.           
  40.           
  41.         //清空所有数据  
  42.         sparseArray.clear();  
  43.           
  44.     }  

SparseBooleanArray和SparseIntArray

SparseBooleanArray和SparseIntArray,其实看名字也知道,它们跟SparseArray极其类似,只是存储类型加以限制了。SparseBooleanArray只能存储boolean值,而SparseIntArray只能存储integer类型的值。它们也同样实现了Cloneable接口,可以直接调用clone方法,也同样是以二分法为依据。而其他的主要方法也是一样的。下面以SparseBooleanArray为简单例子写出主要的方法,从方法看出,两者和SparseArray的确是灰常类似的。SparseIntArray的代码就不再贴出来了,因为都一样的。我们在使用的过程中举一反三,会用一个,其他2个也就会用了呢。

  1. public void testSparseBooleanArray()  
  2.     {  
  3.           
  4. //      SparseBooleanArray sparseBooleanArray = new SparseBooleanArray();  
  5.         //这种创建方式可以设置容器的大小  
  6.         SparseBooleanArray sparseBooleanArray = new SparseBooleanArray(5);  
  7.           
  8.           
  9.         //存入数据,同样有两种方法  
  10.         sparseBooleanArray.put(int, boolean);  
  11.           
  12.         sparseBooleanArray.append(int, boolean);  
  13.           
  14.         //根据key获取对应的boolean值,没有则返回false  
  15.         sparseBooleanArray.get(key);  
  16.         //跟上面类似,valueIfKeyNotFound是自定义的假设不存在则返回的默认值  
  17.         sparseBooleanArray.get(key, valueIfKeyNotFound);  
  18.           
  19.         //获取第5个位置的键值  
  20.         sparseBooleanArray.keyAt(5);  
  21.         //获取第5个元素的值  
  22.         sparseBooleanArray.valueAt(5);  
  23.           
  24.         //删除某个key的元素  
  25.         sparseBooleanArray.delete(key);  
  26.         //清除所有  
  27.         sparseBooleanArray.clear();  
  28.           
  29.     }  

那么SparseBooleanArray和SparseIntArray也和SparseArray一样,存储不是太多的数据,它们都是作为比HashMap更好的选择。但数据是死的,功能也是死的,实现方式是灵活的。条条大路通罗马。我们不能一概而论说谁好谁差,放在具体的场景,才能选择更高效也更合乎成本的实现方式。

SparseArray代替HashMap的更多相关文章

  1. 关于Android中ArrayMap/SparseArray比HashMap性能好的深入研究

    由于网上有朋友对于这个问题已经有了很详细的研究,所以我就不班门弄斧了: 转载于:http://android-performance.com/android/2014/02/10/android-sp ...

  2. SparseArray替代HashMap来提高性能

    SparseArray是 Android框架独有的类,在标准的JDK中不存在这个类.它要比 HashMap 节省内存,某些情况下比HashMap性能更好,按照官方问答的解释,主要是因为SparseAr ...

  3. Android开发 使用SparseArray代替HashMap[转载]

    源作者:Android小Y链接:https://www.jianshu.com/p/1828f14d7955来源:简书 前言 Android开发中,一个好的应用,除了要有吸引人的功能和交互之外,在性能 ...

  4. 73.Android之SparseArray替代HashMap

    转载:https://liuzhichao.com/p/832.html HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定 ...

  5. Android应用性能优化之使用SparseArray替代HashMap

    HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performanc ...

  6. 使用SparseArray代替HashMap

    HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performanc ...

  7. 【移动开发】SparseArray替代HashMap

    SparseArray是android里为<Interger,Object>这样的Hashmap而专门写的class,目的是提高效率,其核心是折半查找函数(binarySearch). p ...

  8. 性能优化:使用SparseArray代替HashMap<Integer,Object>(转)

    HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performanc ...

  9. 用SparseArray代替HashMap

    SparseArray是android提供的一个工具类,它可以用来替代hashmap进行对象的存储,其内部实现了一个矩阵压缩算法,很适合存储稀疏矩阵的. PS:support包中还提供了兼容的类Spa ...

随机推荐

  1. spring boot快速入门 6: 表单验证

    廖师兄源码: https://gitee.com/liaoshixiong/girl 样例:拦截所有未满18岁的女生 第一步:在girl实体类中:添加注解 @Min(value=18 ,message ...

  2. web前端优化之reflow(减少页面的回流)

    1.什么是reflow? reflow(回流)是指浏览器为了重新渲染部分或者全部的文档,重新计算文档中的元素的位置和几何构造的过程. 因为回流可能导致整个Dom树的重新构造,所以是性能的一大杀手. 以 ...

  3. 《LeetBook》leetcode题解(10): Regular Expression Matching——DP解决正则匹配

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  4. Steps to install Docker on Manjaro 16.10--转

    https://manjaro-tutorial.blogspot.com/2016/12/how-to-install-docker-on-manjaro-1610.html Open Termin ...

  5. mysql 索引使用策略及优化

    索引使用策略及优化 MySQL的优化主要分为结构优化(Scheme optimization)和查询优化(Query optimization).本章讨论的高性能索引策略主要属于结构优化范畴.本章的内 ...

  6. ibatis实现批处理

    最近做一个小项目,用到Spring+iBatis.突然遇到一个很久远,却很实在的问题:在Spring下怎么使用iBatis的批处理实现? 大概是太久没有写Dao了,这部分真的忘得太干净了. 从4个层面 ...

  7. 747_Largest-Number-At-Least-Twice-of-Others

    目录 747_Largest-Number-At-Least-Twice-of-Others Description Solution Java solution Python solution 74 ...

  8. 举一反三 willDisplayCell在UICollectionView中的一些应用

    一.UICollectionViewCell动画 上一篇博客写仿58同城实现UITableViewCell动画,同样UiCollectionView中也能用,上一个是从右到左的动画还比较好弄, 但如果 ...

  9. 《Centos服务器版安装教程》

    安装前准备: (1)  首先大家需要在电脑上安装一个VMware (2)  Centos7系列的一个服务器版镜像 有了这两样东西,下面我们就开始安装了 一.     打开VMware,新建一个虚拟机 ...

  10. Docker学习之基本概念

    Docker学习之基本概念 作为一个后端noder,不了解docker有点说不过去,这节开始,学习一些docker层面的东西. 什么是docker Docker最初是dotCloud公司创始人Solo ...