[关闭]
@linux1s1s 2019-02-15T10:36:04.000000Z 字数 2663 阅读 2796

Android 语言级优化小细节

AndroidExtend 2015-10


1. Java的三种遍历在Android上的表现

我们经常看到下面三种Java的遍历方式。

  1. List<String> testList = new ArrayList<String>();
  2. //Init testList here
  3. //Manual testList here
  4. //For Index
  5. final int size = testList.size();
  6. for (int i = 0; i < size; i++) {
  7. final String s = testList.get(i);
  8. //TODO
  9. }
  10. //For Simple
  11. for (String s : testList) {
  12. //TODO
  13. }
  14. //For Interator
  15. for (Iterator iterator = testList.iterator(); iterator.hasNext();) {
  16. String s = (String) iterator.next();
  17. //TODO
  18. }

这些遍历方式迥异,所以有必要探究一下他们在Android上的表现如何
此处输入图片的描述

从上面可以看到for index的方式有更好的效率,但是因为不同平台编译器优化各有差异,我们最好还是针对实际的方法做一下简单的测量比较好,拿到数据之后,再选择效率最高的那个方式。(一般建议选择for index的方式遍历)

2. 在Android开发中选择合适的Map

我们经常会使用到HashMap这个容器,它非常好用,但是却很占用内存。为了解决HashMap更占内存的弊端,Android提供了内存效率更高的ArrayMap。它内部使用两个数组进行工作,其中一个数组记录key hash过后的顺序列表,另外一个数组按key的顺序记录Key-Value值。
因为ArrayMap在存储上是连续的。不像HashMap是不连续的,所以ArrayMap的插入与删除的效率是不够高的,但是如果数组的列表只是在一百这个数量级上,则完全不用担心这些插入与删除的效率问题。HashMap与ArrayMap之间的内存占用效率对比图如下:

此处输入图片的描述

不服可以来看一下ArrayMap的构造器

  1. /**
  2. * Create a new empty ArrayMap. The default capacity of an array map is 0, and
  3. * will grow once items are added to it.
  4. */
  5. public ArrayMap() {
  6. mHashes = ContainerHelpers.EMPTY_INTS;
  7. mArray = ContainerHelpers.EMPTY_OBJECTS;
  8. mSize = 0;
  9. }

上面说了辣么多废话,之类小结一下Map的使用。

  1. //使用HashMap处理数据(数量级在千级别以上)
  2. HashMap<String, String> configMap = new HashMap<String, String>();
  3. //方式一
  4. for (Iterator iterator = configMap.entrySet().iterator(); iterator.hasNext();) {
  5. Map.Entry<String, String> entry = (Entry<String, String>) iterator.next();
  6. String key = entry.getKey();
  7. String value = entry.getValue();
  8. }
  9. //或者另外一种等效方式
  10. Iterator<Entry<String, String>> iterator = configMap.entrySet().iterator();
  11. while (iterator.hasNext()) {
  12. Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
  13. String key = entry.getKey();
  14. String value = entry.getValue();
  15. }
  16. //方式二
  17. Iterator<String> iterator2 = configMap.keySet().iterator();
  18. while (iterator2.hasNext()) {
  19. String key = iterator2.next();
  20. String value = configMap.get(key);
  21. }
  22. //使用ArrayMap处理数据(数量级在百级别)
  23. ArrayMap<String, String> configMapRefine = new ArrayMap<String, String>();
  24. for (int i = 0; i < 500; i++) {
  25. String key = configMapRefine.keyAt(i);
  26. String value = configMapRefine.valueAt(i);
  27. }

另外还有一种Android专门优化的Map-SparseArray,什么情况下适用SparseArray呢?

此处输入图片的描述

看清楚,只有在Map<Integer, String>这种情况下才适用SparseArray替换

  1. SparseArray<String> sparseArray = new SparseArray<String>();
  2. for (int i = 0; i < sparseArray.size(); i++) {
  3. int key = sparseArray.keyAt(i);
  4. String value = sparseArray.valueAt(i);
  5. }

具体在性能上能优化多少可以参考 SparseArray替代HashMap来提高性能

3. 请在情非得已的情况下使用Enum

关于Enum,Android官方开发文档有这么一句话:
此处输入图片的描述

Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.

关于enum的效率,请看下面的讨论。假设我们有这样一份代码,编译之后的dex大小是2556 bytes,在此基础之上,添加一些如下代码,这些代码使用普通static常量相关作为判断值:
此处输入图片的描述
增加上面那段代码之后,编译成dex的大小是2680 bytes,相比起之前的2556 bytes只增加124 bytes。假如换做使用enum,情况如下:
此处输入图片的描述
使用enum之后的dex大小是4188 bytes,相比起2556增加了1632 bytes,增长量是使用static int的13倍。不仅仅如此,使用enum,运行时还会产生额外的内存占用,如下图所示:
此处输入图片的描述

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注