性能优化是所有设备都需要考虑的问题,我先写一下15年google推荐的性能优化方案。标记[]的下面会有详解。本人目前也在学习阶段,如果有些知识点写的不正确, 还请各位大神指点。
原文如下链接:
http://hukai.me/android-performance-patterns/#disqus_thread
简单总结如下:
性能优化的问题可分为三类:渲染机制、内存、电量
渲染机制[1]:
原因 | 检查工具 | 解决 |
---|---|---|
布局复杂 | HierarchyViewer(DDMS) | 减少无用的布局 |
Overdraw(过度绘制) | Show GPU Overdraw(开发者选项) | OpenGL ES**[2]/只刷新部分布局[3]** |
动画执行次数过多 | TraceView(DDMS) | 减少动画执行次数 |
内存与GC:
Android有自动管理内存的机制[4],超出阈值后垃圾回收器会自动回收。但是,垃圾回收器在工作的时候,所有线程都会暂停,所以,要尽量减少垃圾回收器工作的时间。垃圾回收器工作时间的长短与其在哪个区域内工作有关,还和要处理的对象数量有关。
解决方案:
- 不做不必要的工作:如,尽量少抽取方法,代码能简则简
- 不申请不必要的内存
- int比Integer占用更少的内存
- 如果你的方法不需要访问类字段,那么让你的方法是static的吧,这将会带来15%-20%速度的提升。
- 常量尽量使用static and final定义。如果使用final定义常量之后,会减少编译器在类生成时初始化方法调用时对常量的存储,对于int型常量,将会直接使用其数值来进行替换,而对于String对象将会使用相对廉价的“string constant”指令来替换字段查找表。
- 你明明知道一个方法返回一个String之后,你需要对这个String重新进行修改。那么就不要返回一个String,返回一个StringBuffer会是你更好的选择。
- 数组比一个Map拥有更好的性能。
- 避免Getters/Setters。
- 使用最新的循环方式。如增强for。
- 避免使用浮点类型。
电量:
- 我们应该尽量减少唤醒屏幕的次数与持续的时间,使用WakeLock来处理唤醒的问题,能够正确执行唤醒操作并根据设定及时关闭操作进入睡眠状态。
- 某些非必须马上执行的操作,例如上传歌曲,图片处理等,可以等到设备处于充电状态或者电量充足的时候才进行。
- 触发网络请求的操作,每次都会保持无线信号持续一段时间,我们可以把零散的网络请求打包进行一次操作,避免过多的无线信号引起的电量消耗。关于网络请求引起无线信号的电量消耗,还可以参考这里http://hukai.me/android-training-course-in-chinese/connectivity/efficient-downloads/efficient-network-access.html
不想写太多,但是需要解释的原理也有很多,索性都在下面写出来吧。
1. 渲染机制
用户可感知到的卡顿多是因为渲染性能的问题。
- 渲染机制的原理:Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,画面看起来才会流畅。
- VSYNC信号:将硬件在一秒内刷新屏幕的次数(Hz)与GPU在一秒内绘制操作的帧数(fps)同步起来。
- 16ms:人眼与大脑之间的协作无法感知超过60fps的画面更新。所以,每一帧的绘制时间有1000ms/60fps = 16ms/帧。
2. OpenGL ES
OpenGL ES是OpenGL的一个子集,专门用于手机、游戏主机的图形优化。
用法与ViewHolder相似,就是提前将要渲染的布局存到GPU的内存中,在需要时取出。
3. 只刷新部分布局
这里只介绍两个方法:
- 通过canvas.clipRect()指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。
- 通过canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作。
4. 内存管理机制
Android系统内部有一个内存管理机制(Generational Heap Memory)。分为三个Generation区域,分别是:Young Generation,Old Generation,Permanent Generation。
最近创建的对象会被放到Young Generation中,在Young Generation中呆一定的时间后,会被移动到Old Generation中,最后是Permanent Generation。
上面说到,GC在执行时线程都会暂停,所以要减少GC的执行时间,GC被触发的原因有:
- Memory Churn(内存抖动),内存抖动是因为大量的对象被创建又在短时间内马上被释放。
- 占用Generation的内存区域达到阀值时,也就是剩余空间不够的时候,会触发GC。
GC执行时间的长短与哪一个Generation和对象数量有关。