莫问天涯路几重,轻衫侧帽且从容。这篇文章主要讲述Android开发中的性能优化---代码相关的知识,希望能为你提供帮助。
前这篇主要总结一些优化代码的技巧,一些写代码中的小细节,可能就会影响程序的执行效率!!!
主要遵循两个原则
1.不要创建一些没必要创建的对象以及重复定义某个变量
对象的创建是一个非常繁琐的步骤,JVM首先会对通过new
指令对符号进行解析,以此来判断该类是否被加载,然后在堆中进行内存分配,为对象分配完内存空间后,就会对内存区域进行初始化(该为0的为0,该为null的为null,这也是为什么方法中的变量需要程序员显示初始化),最后JVM会调用对象的构造函数,而且一般都会有一个变量建立该对象的引用。
所以,创建对象是很麻烦的,就不要没事干就创建对象了。
2.用完的对象要及时回收
就是常说的GC,这里要明确的是,什么时候进行GC操作,不是由程序员决定的,JVM会在有必要的时候自行启动GC,程序员只能做到建议JVM尽快对某对象进行GC,它有两个评判标准
(1) 该对象失去引用,那么最好的办法就是将不用的对象赋值为null
(2) 该对象离开作用域,比如说方法执行完毕,局部变量和对象就会被回收,所以尽可能少生命全局变量。
并且GC操作也是要耗内存的@_@!
开始1.最频繁的 + 和 +“” 操作java中的 +号既可以进行数值计算,又可以进行字符串操作,但是在进行字符串操作的时候,它是一种效率很低的方式,虽然用起来非常非常方便!
1.1 不要直接使用 +号 进行字符串拼接
开发中使用“+”号运算符的确非常方便,但是效率也非常低,因为“+”号内部实际上调用的是StringBuffer
的append()
方法,然后再转换成String
,那么它肯定没有直接调用快。
还有一个就是StringBuilder
,这个类是Java1.5时出来的,从效率上来说,它和StringBuffer
区别在于StringBuilder
不是线程安全的,多线程操作会出现问题,那么就比较容易选择了,
在单线程中,使用StringBuilder
,在多线程中使用StringBuffer
1.2 不要直接使用 +“” 来进行字符串转化
将对象转化成字符串的操作有三种,效率从快到慢依次是,xxx.toString
、String.valueOf(xxx)
、
xxx +""
xxx.toString
是直接转化,而String.valueOf(xxx)
底层是调用了toString()
方法,至于+""
,在1.1时已经说了,它会先转化成SringBuffer
,然后再调用toString()
,所以结果一目了然
上述两点可以看下面的代码
文章图片
通过javap -c 的指令, 能够看到下面的内容, 虽然左边的不一定能看懂, 但是右边的注释很容易理解
文章图片
2.循环的使用细节(以for为例)循环是开发中频率出现很高的一种操作,它的作用就是简化重复的步骤,比如说添加10000条数据到某个集合中,如果不用循环,即使复制粘贴也要好久,但是通过循环操作就可以几行代码完成。但这里面就会容易出现一些小的细节,有可能就会影响程序的执行效率。以下代码举例:
1 List< String> list = new ArrayList< > (); 2 for (int i = 0; i < 100; i++) { 3Random random = new Random(); 4Integer result = random.nextInt(100); 5String s = result.toString(); 6list.add(s); 7 }
2.1 尽量不要在循环中创建不必要的对象
示例代码中在for循环中创建了100个Random对象,而实际进行随机数操作的是该对象的
nextInt()
方法,那么实际上可以写成:List< String> list = new ArrayList< > (); // 对象创建在for循环外 Random random = new Random(); for (int i = 0; i < 100; i++) { Integer result = random.nextInt(100); String s = result.toString(); list.add(s); }
2.2 不用的对象要及时回收
这里只是举个例子,实际开发中有可能出现的情况是,解析一段Json,然后获取到了Json中的某个对象并添加到了集合中,那么这个被解析过的对象其实就没什么用了,因为数据已经添加到了集合中,比较我们要用的是数据而不是对象,此时就可以置为null,让JVM尽快的回收掉它,这是一个非常好的习惯,
但有些时候例外, 面这种情况, 将对象置为null, 但实际上该对象的引用仍然被list集合所持有, 所以对象不会被回收掉
1 List< String> list = new ArrayList< > (); 2 Random random = new Random(); 3 Integer result; 4 String s; 5 for (int i = 0; i < 100; i++) { 6result = random.nextInt(100); 7s = result.toString(); 8list.add(s); 9result = null; // 此时虽然将对象置为null, 但是它的引用依然是被list所持有的, 即使result置为null, 仍然不会来回收 10s = null; 11 }
比较好的做法应该是清空list集合然后将list置为null
1 list.clear(); // 要先将list所持有的对象给清空掉 2 if(list != null) { 3list = null; 4 }
在实际开发中, 可以写在onDestory()方法中
2.4 适当的建立方法结果的缓存
比如有时候为了简便会这样写
文章图片
Java在调用某个方法时,其实也不是那么简单,要创建栈帧来存储局部变量表,操作数栈,动态连接,方法返回地址,还要方法调用现场、恢复方法调用现场等一系列操作。所以,如果list的size()非常大时,也会影响效率,所以可以定义一个变量而不是直接使用
文章图片
3. if和switch的使用既然有了循环,那么就应当有判断@_@!
3.1 通过if来在合适的时候创建对象或调用方法
这个也算一个小细节
文章图片
这个循环里面可以看出,只有在随机数为20的时候集合才会添加该数据,所以在此之前,将随机数调用
toString()
方法毫无意义。所以可以写为
文章图片
4 使用位运算来代替乘除运算计算机只懂二进制,而位运算就是直接的二进制运算,所以当然效率比较高,
当然也有缺点
(1) 对于数字过大,还是直接乘除比较方便
(2) 代码的可读性不高
5 合理利用Activity的生命周期Activity的生命周期最常用的莫过于
onCreate()
,但是其它的生命周期我想也很有必要恰当的利用。
文章图片
这个仅仅是个人书写习惯,不知道会不会影响到性能,但是最起码这样写代码结构比较清晰 :)
6 使用Zipalign来进行代码对齐Zipalign是一个SDK下的工具,能够对apk文件中未压缩的数据在4个字节边界上对齐,当资源文件通过内存映射对齐到4字节边界时,android系统就可以通过调用mmap函数读取文件,
mmap函数是Linux系统的调用函数,提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作,进程可以像读写内存一样对普通文件的操作,不必再read()和write(),在读取资源上获得较高的性能。如果资源本身没有进行对齐处理,它就必须显式地读取它们——这个过程将会比较缓慢且会花费额外的内存。
具体用法我会在工具篇中总结
7 使用SparseArray代替HashMap使用
SparseArray
来代替HashMap
,原因是一次Android Studio的提示,
文章图片
使用
SparseArray
比HashMap
好,所以就网上查找了些SparseArray
的一些相关资料
简单的来讲,
SparseArray
适用于HashMap<
Integer, Object>
这样的结构,因为SparseArray
内部是用的int
型数组存储key
和Object
型的数组存储value
的值,省去了int
包装成Integer
的过程.
文章图片
根据这篇文章,可以看出来,在数据过多时,效率上
SparseArray
并没有比HashMap
更快,但是该文章作者结尾处说内存的使用状况上,能够节约27%
文章图片
而这篇文章的作者专门对内存的使用状况做了测试,说是内存上优化了35%
文章图片
我通过Android Studio自带的工具观察内存消耗,使用
HashMap
大约在3.24~3.31
文章图片
而
SparseArray
大约在3.0~3.1之间
文章图片
不过具体优化了多少不是重点,反正是对内存开销上
SparseArray开销更低
更具有优势~!
另外除了
SparseArray
,ArrayMap
,SparseBoolMap,SparseIntMap,SparseLongMap,LongSparseMap等等一些列API,在内存使用方面都相对于HashMap要好的多8 I/O流尽量使用带Buffer的带Buffer缓冲区的I/O对象效率要比不带的高一些,
9. 能不static就不static,能final就final
static
虽然让成员用起来很爽,但是会延长它们的生命周期
final
会使对象无法被继承,变量无法被修改,方法无法被重写,并且会进行内联结束暂时想到的就这么多了,仅仅是一些开发中的细节部分,有些众所周知的就没写,比如复用
ListView
的ConvertView
,压缩图片、异步加载等等,【Android开发中的性能优化---代码】如有错误, 敬请指正, 感激不尽!
推荐阅读
- Office Web Apps 错误日志
- 第一行代码Android pdf
- Android开发之漫漫长途 Fragment番外篇——TabLayout+ViewPager+Fragment
- Android开发遇到的坑-----融云聊天接收到但不能显示
- Android开发遇到的坑-----融云2.8.+版本修改插件列表
- android编程权威指南 第三版 pdf
- Android开发中的性能优化---布局
- Android开发遇到的坑-----微信分享问题
- Android开发遇到的坑-----添加依赖遇到DuplicateFileException