这是我在学习过程中总结的知识
目的是希望日后回来看或者需要用的时候可以 一目了然 # 的回顾、巩固、查缺补漏
不追求详细相当于书本的精简版或者说是导读(想看详细的直接对应翻书),但会尽力保证读者都能快速理解和快速使用(随理解加深会总结的更加精简),但必要时会附上一些较详细解释的链接
脚注是空白的:表示还没弄懂的知识,了解后会添加
本章介绍
- 常见的性能优化方法
- 提供程序的可维护性和可扩展性的思想
15.1 Android的性能优化方法
15.1.1 布局优化
核心思想——减少布局文件的层级
- 删除布局中无用的空间和层级
- 使用性能较低的ViewGroup,比如LinearLayout比RelativeLayout简单,耗能少
- 采用include标签(布局重用)、merge标签(结合include,减少布局层级)和ViewStub(提供按需加载)
merge
两个竖直方向的LinearLayout,可以用merge去除被包含的LinearLayout
ViewStub
ViewStub继承了View
在网络异常时的界面,就没必要加载整个界面
15.1.2 绘制优化
是指View的onDraw方法要避免执行大量的操作
- onDraw中不要创建新的布局对象
- onDraw不要做耗时的任务,也不能是成千上万次的循环操作
15.1.3 内存泄露的优化
内存泄露的优化分为两个方面
- 开发过程中避免写出有内存泄漏的代码
- 通过分析工具比如MAT来找出潜在的内存泄露然后解决
1. 静态变量导致的内存
这些静态变量会导致Activity无法正常销毁
private static Context sContext;
private static View sView;
private Button mButton;
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sContext = this;
sView = new View(this);
}
2. 单例模式导致的内存泄露
首先提供一个单例模式的类,可以接收外部的注册并将外部的监听器存储起来
package com.ryg.chapter_15.manager;
import java.util.ArrayList;
import java.util.List;
public class TestManager {
private List<OnDataArrivedListener> mOnDataArrivedListeners = new ArrayList<OnDataArrivedListener>();
private static class SingletonHolder {
public static final TestManager INSTANCE = new TestManager();
}
private TestManager() {
}
public static TestManager getInstance() {
return SingletonHolder.INSTANCE;
}
public synchronized void registerListener(OnDataArrivedListener listener) {
if (!mOnDataArrivedListeners.contains(listener)) {
mOnDataArrivedListeners.add(listener);
}
}
public synchronized void unregisterListener(OnDataArrivedListener listener) {
mOnDataArrivedListeners.remove(listener);
}
public interface OnDataArrivedListener {
public void onDataArrived(Object data);
}
}
现在让Activity实现OnDataArrivedListener接口并向TestManager注册监听,但是下面代码由于缺少解注册的操作所以会引起内存泄露
原因是Activity的对象被单例模式的TestManager所持有,而单例模式的特点是其生命周期和Application保持一致,因此Activity对象无法被及时释放
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sContext = this;
TestManager.getInstance().registerListener(this);
3. 属性动画导致的内存泄露
属性动画中有一类无限循环的动画,如果没有在onDestroy中去停止,那么动画会一直播放下去.这个时候Activity的View 被动画持有,而View又持有了Activity,最终Activity无法被释放
解决方法是调用animator.cancel()方法
15.1.4 响应速度优化和ANR日志分析
Android规定,Activity如果5秒钟内无法响应屏幕触摸事件或者键盘输入事件就会出现ANR
BroadcastReceiver如果10秒钟之内还未执行完操作也会出现ANR
当一个进程发生了ANR以后,系统会在/data/anr目录下创建一个traces.txt文件,我们需要分析这个文件找出问题
15.1.5 ListView和Bitmap优化
ListView
- 首先采用ViewHolder并避免在getView中执行耗时操作
- 根据列表的滑动状态来控制任务的执行频率,比如快速滑动时不要开启大量的异步任务
- 尝试开启硬件加速
Bitmap
- 通过BitmapFactory.Options来根据图片采样缩放
15.1.6 线程优化
- 使用线程池避免程序中存在大量的Thread
- 线程池控制线程并发,放置出现阻塞现象
15.1.7 一些性能优化建议
- 避免创建过多对象
- 不要过多使用枚举
- 常量使用static final 来修饰
- 使用一些Android特有的数据结构,比如SparseArray和Pair等,性能更好
- 适当使用软引用和弱引用
- 采用内存缓存和磁盘缓存’
- 尽量采用静态内部类,避免潜在的由于内部类导致的内存泄露
15.2 内存泄露分析之MAT工具
15.3 提高程序的可维护性
- 私有成员以m开头
- 静态成员以s开头