@linux1s1s
2019-02-15T18:36:04.000000Z
字数 2663
阅读 3515
AndroidExtend
2015-10
我们经常看到下面三种Java的遍历方式。
List<String> testList = new ArrayList<String>();
//Init testList here
//Manual testList here
//For Index
final int size = testList.size();
for (int i = 0; i < size; i++) {
final String s = testList.get(i);
//TODO
}
//For Simple
for (String s : testList) {
//TODO
}
//For Interator
for (Iterator iterator = testList.iterator(); iterator.hasNext();) {
String s = (String) iterator.next();
//TODO
}
这些遍历方式迥异,所以有必要探究一下他们在Android上的表现如何
从上面可以看到for index的方式有更好的效率,但是因为不同平台编译器优化各有差异,我们最好还是针对实际的方法做一下简单的测量比较好,拿到数据之后,再选择效率最高的那个方式。(一般建议选择for index的方式遍历)
我们经常会使用到HashMap这个容器,它非常好用,但是却很占用内存。为了解决HashMap更占内存的弊端,Android提供了内存效率更高的ArrayMap。它内部使用两个数组进行工作,其中一个数组记录key hash过后的顺序列表,另外一个数组按key的顺序记录Key-Value值。
因为ArrayMap在存储上是连续的。不像HashMap是不连续的,所以ArrayMap的插入与删除的效率是不够高的,但是如果数组的列表只是在一百这个数量级上,则完全不用担心这些插入与删除的效率问题。HashMap与ArrayMap之间的内存占用效率对比图如下:
不服可以来看一下ArrayMap的构造器
/**
* Create a new empty ArrayMap. The default capacity of an array map is 0, and
* will grow once items are added to it.
*/
public ArrayMap() {
mHashes = ContainerHelpers.EMPTY_INTS;
mArray = ContainerHelpers.EMPTY_OBJECTS;
mSize = 0;
}
上面说了辣么多废话,之类小结一下Map的使用。
//使用HashMap处理数据(数量级在千级别以上)
HashMap<String, String> configMap = new HashMap<String, String>();
//方式一
for (Iterator iterator = configMap.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, String> entry = (Entry<String, String>) iterator.next();
String key = entry.getKey();
String value = entry.getValue();
}
//或者另外一种等效方式
Iterator<Entry<String, String>> iterator = configMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
String key = entry.getKey();
String value = entry.getValue();
}
//方式二
Iterator<String> iterator2 = configMap.keySet().iterator();
while (iterator2.hasNext()) {
String key = iterator2.next();
String value = configMap.get(key);
}
//使用ArrayMap处理数据(数量级在百级别)
ArrayMap<String, String> configMapRefine = new ArrayMap<String, String>();
for (int i = 0; i < 500; i++) {
String key = configMapRefine.keyAt(i);
String value = configMapRefine.valueAt(i);
}
另外还有一种Android专门优化的Map-SparseArray,什么情况下适用SparseArray呢?
看清楚,只有在Map<Integer, String>
这种情况下才适用SparseArray
替换
SparseArray<String> sparseArray = new SparseArray<String>();
for (int i = 0; i < sparseArray.size(); i++) {
int key = sparseArray.keyAt(i);
String value = sparseArray.valueAt(i);
}
具体在性能上能优化多少可以参考 SparseArray替代HashMap来提高性能 。
关于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,运行时还会产生额外的内存占用,如下图所示: