布局优化
首先删除布局中无用的控件和层级,其次有选择地使用性能较低的ViewGroup
在CPU的使用度上,RelativeLayout使用的时间比LinearLayout要多。因此,如果能使用LinearLayout的话,就不要使用RelativeLayout。不过大多数的时候,单独使用一种布局无法完成界面的部署,因此需要通过“嵌套”的方式来完成。
如果不得已使用嵌套布局的话,建议采用RelativeLayout,因为ViewGroup的嵌套就相当于增加了布局的层数,同样会降低程序的性能。
另外一种手段是采用<include>标签、<merge>标签和ViewStub
<include>标签主要用于布局重用
<merge>标签一般配合<include>配合使用,它可以降低减少布局的层级
ViewStub提供了按需加载的功能
<include>加载布局文件示例:
绘制优化
绘制优化是指onDraw方法要避免执行大量的操作。
- onDraw中不要创建新的局部对象。这是因为onDraw方法可能会被频繁调用,这样就会在一瞬间产生大量的临时对象。
- onDraw方法中不要做耗时的任务,也不能执行成千上万次的循环操作,这会造成View的绘制过程不流畅。
内存泄露优化
1、静态变量导致的内存泄露
在dalvik虚拟机中,static变量所指向的内存引用,如果不把它设置为null,GC是永远不会回收这个对象的。
public class MainActivity extends Activity{
public static Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
}
}
解决办法:在onDestroy()方法中将mContext = null; 处理。
2、单例模式导致的内存泄漏
public class SingletonA {
private static SingletonA mSingletonA;
public static SingletonA getInstance(){
if (mSingletonA == null) {
return new SingletonA();
}
else
return mSingletonA;
}
//constructor
public SingletonA(){}
//other methods
}
接下来在Activity中对这个类进行使用:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SingletonA instanceF = SingletonA.getInstance(this);
//在当前代码中使用this将此activity的实例给了静态变量,导致activity退出以后无法被释放
}
3、属性动画导致的内存泄露
从Andorid 3.0开始出现属性动画,属性动画中有一类无限循环的动画,如果不在onDestroy中去停止动画,那么动画会一直播放下去,尽管已经无法在界面上看到动画效果了,并且这个时候Activity的View会被动画持有,而View又持有了Activity,最终Activiy无法释放。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton = findViewById(R.id.button);
ObjectAnimator animator = ObjectAnimator.ofFloat(mButton,"rotation",0,360).setDuration(2000);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.start();
}
解决方法是在Activity的onDestroy中调用animator.cancel()来停止动画。
响应速度优化和ANR日志分析
Android规定,Activity在5秒内无法响应屏幕触摸事件或者键盘输入事件出现ANR。BroadcastReceiver在10秒内未执行操作会出现ANR。
定位ANR:在/data/anr目录下的文件traces.txt,通过分析这个文件能定位ANR的原因。
如下面的代码:
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(Runnable.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
testANR();
}
}).start();
SystemClock.sleep(10);
initView();
}
private synchronized void testANR(){
}
private synchronized void initView(){
}
虽然testANR()和initView()不在同一个线程上,但是因为他们都要获取同一个对象的锁(this),因此也会发生子线程与主线程抢同一个锁的情况。
ListView和Bitmap优化
ListView:
1、首先要采用ViewHolder并避免在getView中执行耗时操作
2、其次要根据列表的滑动状态来控制任务的执行频率,比如当列表快速滑动时显然是不太适合开启大量的异步任务的。
3、尝试开启硬件加速来使ListView的滑动更加流畅。
线程优化
- 避免创建过多的对象
- 不要过多使用枚举,枚举占用的内存空间比整型要大
- 常量请使用 static final 来修饰
- 使用一些Android特有的数据结构,例如SparseArray 和 Pair 等,它们都具有更好的性能
- 适当使用软引用和弱引用
- 采用内存缓存和磁盘缓存
- 尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄露