Android程序不能无限制的使用设备的内存和CPU。正如经典所说,设备的资源不是给程序员用的,是给用户用的。在编写程序时,应该经常注意内存和CPU的使用。
在Android中,过多的使用内存容易导致OOM,过多的使用CPU容易导致手机卡顿甚至ANR。常见的优化方面有:
- 布局优化
- 绘制优化
- 内存泄漏优化
- 响应速度优化
- 列表List优化
- Bitmap优化
- 线程优化
布局优化
-
布局的核心是尽量扁平,不要嵌套。
- 删除无用的控件和层级
- 使用性能较高的
ViewGroup。能用LinearLayout代替RelativeLayout的就尽量用。但是如果使用LinearLayout会产生嵌套布局,那还是用Relativelayout好,布局嵌套越少越好。
-
使用
includemergeViewStub标签<include>用于复用布局。<merge>和<include>一起使用,用于剔除多余的ViewGroup。如果当前布局是竖向的LinearLayout,include进来的布局根布局也是竖向的LinearLayout,使用<merge>就能去掉多余的这层布局。<ViewStub>用于按需加载布局。使用 ViewStub 标签引入的布局,默认不会被加载,只有通过 ViewStub 的setVisibility或者inflater方法加载后,ViewStub 就会被它引入的布局替换掉。
绘制优化
在View的onDraw中要避免执行大量的操作:
- 不用创建大量的局部变量。
onDraw方法会被频繁调用,如果一瞬间产生大量临时对象,不仅占用过多内存,还用于引起GC,从而造成卡顿。 - 不要做耗时操作,也不能执行千万级循环。每帧的绘制时间不要超过16ms(1000/60fps)。
内存泄漏优化
- 静态变量引用了
ContextActivity对象,会造成内存泄漏。 - 单列模式导致的内存泄漏。单列的生命周期和 Application 的生命周期一致。单列如果引用了Activity,Activity销毁之后,一直到程序结束都不会被回收。造成内存泄漏。
- 属性动画导致内存泄漏。属性动画如果在Activity结束时没有被
cancle,就会导致 Activity 不能被释放,造成内存泄漏。解决方法是,在 Activity 的 onDestroy 中调用animator.cancel()停止动画。 - Handler 导致的内存泄漏。在 Activity 中创建的Handler持有Activity的引用。如果当 Activity 结束之后,handler所在的线程还在执行,就会造成 Activity 不能被释放。解决方法是,Handler持有Activity的弱引用(
WeakReference)。
响应速度优化
- 避免在主线程做耗时操作。
Activity5秒没有响应触摸或键盘输入就会触发ANR。BroadcastReceiver10秒没有执行完操作也会触发ANR。 - 当一个进程发生
ANR之后,系统会在data/anr目录下创建一个tracks.txt文件记录原因。可以上传该文件到服务器进而分析ANR原因。
列表优化
- ListView 采用 ViewHolder 避免在
getView中执行耗时操作 - 通过列表的滑动状态来控制加载任务。比如滑动时,不加载网络图片,不进行异步任务。
- 可以尝试开启硬件加速,提升滑动质量。
Bitmap优化
- 边界压缩。通过设置
options.inJustDecodeBounds = true;只加载图片边界,获取图片的尺寸等信息。 - 质量降低。通过修改
Bitmap.Config修改解码的颜色空间。 - 缩放图片。通过修改
options.inSampleSize压缩图片尺寸。 - 使用缓存。使用
LurCache在内存中缓存Bitmap,使用DiskLruCache实现磁盘缓存。
线程优化
- 使用线程池控制线程数量和复用线程
其他优化
- 常量使用
static final修饰 - 使用Android的特有数据结构:
ArrayMap代替HashMapSpareseArray代替以Integer为key的ArrayList。如ArrayList<Integer,Object>。Pair成双成对的数据。
- 尽量采用静态内部类。可以避免非静态内部类隐式持有外部类的引用,造成内存泄漏。(比如推荐在Activity使用静态内部类的Handler)。
- 合理使用
WeakReference和SoftReference。