Android性能优化

Android的性能优化在开发中尤为重要,每个开发者都应该掌握性能优化的一些知识,避免开发出性能不佳的应用。此篇内容是《Android开发艺术探索》的读书笔记。

Android性能优化的方法

布局优化

  1. 尽量减少布局文件的层级
  2. 如果布局中国既可以使用LinearLayout又可以使用RelativeLayout,那么采用LinearLayout
  3. 使用标签重用布局
  4. 使用标签和标签一起减少布局层级
  5. 使用ViewStub延迟加载不需要的布局,ViewStub标签不能和标签一起使用。

绘制优化

  1. 在onDraw方法中不要创建新的局部对象,因为onDraw方法会被重复调用
  2. 在onDraw方法中尽量不要做耗时的操作,尽量减少使用循环,因为循环会抢占CPU的时间片,造成绘制过程不流畅。

内存泄露优化

内存泄露的常见场景:

  1. 静态变量导致的内存泄露
  2. 单例模式导致的内存泄露
  3. 属性动画导致的内存泄露

响应速度优化和ANR日志分析

出现ANR的场景:

  1. Activity如果5秒钟内无法响应屏幕触碰事件或键盘输入事件就会出现ANR;
  2. BroadcastReceiver如果10秒钟内还未执行完操作也会出现ANR

响应速度优化的核心思想是避免在主线程中做耗时操作。当一个进程发生了ANR后,系统会在data/anr目录下创建一个文件trace.txt,通过分析这个文件可以定位出ANR的原因。

ListView和Bitmap优化

ListView优化主要分为3个方面:

  1. 采用ViewHolder并避免在getView中执行耗时操作
  2. 根据列表的滑动状态来控制人物的执行频率,比如当列表快速滑动时显然是不太适合开启大量的异步任务的。
  3. 尝试开启硬件加速来使ListView的滑动更加流畅

Bitmap的优化在于对图片进行采样,获取采样率可以通过如下的流程:

  1. 将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片
  2. 从BitmapFactory.Options中取出图片的原始宽高的信息,它们对应于outWidth和outHeight参数
  3. 根据采样率的规则并结合目标View的所需大小计算出采用率inSampleSize
  4. 将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth,int reqHeight) {
//First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res,resId,options);
//Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
//Decode bitmap with inSampleSize set
option.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res,resId,options);
}
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,int reqHeight) {
//Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if(height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
//Calculate the largest inSampleSize value that is a power of 2 and keep both
//height and width larger than the requested height and width.
while((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}

线程优化

线程优化的思想是采用线程池,避免程序中存在大量的Thread,避免线程的创建和销毁所带来的性能开销,同时线程池还能有效的控制线程池的最大并发数,避免大量的线程因互相抢占系统资源从而导致阻塞现象的发生。

一些性能优化建议

  • 避免创建过多的对象
  • 不要过多使用枚举,枚举占用的内存空间要比整型大
  • 常量请使用static final 来修饰
  • 使用一些Android特有的数据结构,比如SparseArray和Pair等,它们都具有更好的性能
  • 适当使用软引用和弱引用
  • 采用内存缓存和磁盘缓存
  • 尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄露