2.39 Android性能优化笔记
2.39.1 启动加速
- 冷启动(App在设备刚启动或者应用被kill后首次启动即冷启动)
    - 冷启动的开始, 系统会执行以下三个任务
        - 加载启动App
- 启动后显示空白window
- 创建app的process
 
- 创建app的process后马上执行以下任务
        - 创建App对象
- 启动main thread
- 创建Main Activity
- inflating views
- Laying out the screen
- 执行首次draw(用户可以使用app)
 
- 问题: 1). Application#onCreate()负载过重, 2).Activity创建, 包含初始化values, 调用构造方法, 调用Activity生命周期方法
 
- 冷启动的开始, 系统会执行以下三个任务
        
- 
    热启动, 进程和 Activity未被kill掉, 系统把App的Activity重新拿到前台展示
- 
    暖启动, 1). 用户返回并重新启动, 当进程可运行而 Activity需要重新创建; 2). 系统清除应用内存, 进程和Activity需要重新启动
- 
    优化: 1). 避免在 Application#onCreate或者MainActivity过重的初始化; 2). 定位问题: 避免I/O操作, 反序列化, 网络操作和布局嵌套, 3). 尽可能利用虚拟文件系统的page cache, 减少IO, 查找发生IO的文件,按时间顺序统计启动阶段的所有文件,排布在一起,这样发生少量 IO,就能全部读到 cache 中 安装包重排布
- 排查方法
    - ADB命令: ` adb shell am start -W xxx/.XXXActivity, 该指令给出三个时间, 1). ThisTime: 最后一个启动Activity`的启动耗时, 2). TotalTime: 自己的所有Activity的启动耗时, 3). WaitTime: AMS启动App的Activity的总时间
- TraceView
 
- ADB命令: ` adb shell am start -W xxx/.XXXActivity
布局优化
- OverDraw(过度绘制)
    - 多层布局设置背景色导致OverDraw
- 嵌套层次太深
 
- 优化策略
    - 减少重复设置背景色
- 优化View的层级嵌套
- merge标签, 可以合并布局, 减少布局的层级- merge多用于顶替顶层- FrameLayout或者- include布局时, 消除因为引用布局导致的多余嵌套
- ViewStub标签, 延迟创建或初始化, 需要调用- ViewStub#inflate()或者- ViewStub#setVisibility()显示
- 自定义控件, 在onDraw不能进行复杂运算
 
- 排查方法
    - Hierarchy View工具可排查View的层级以及绘制流程的耗时
- TraceView
- 开发者选项->调试GPU过度绘制->显示过度绘制区域
- UIAutoMatorViewer, 只能查看布局层次
 
内存优化
- 常见内存泄露
    - handler内存泄露(匿名内部类)
- TimerTask内存泄露(匿名内部类)
- 资源性对象未关闭(SQLite的Cursor或File)
- 系统源码泄露, 如InputManager, 或错误使用其它如WiFiManager
- 非静态内部类(持有外部类引用)
- WebView
 
- OOM问题
    - Java堆内存溢出, 为对象分配内存时达到进程的内存上限。由Runtime.getRuntime.MaxMemory()可以得到Android中每个进程被系统分配的内存上限,当进程占用内存达到这个上限时就会发生OOM
- 无足够连续内存空间
- FD数量超出限制
- 线程数量超出限制
- 虚拟内存不足
 
- 优化策略
    - 节制使用Service
- 使用优化的集合, 如SparseArray等
- 少用枚举
- 使用protobuf序列化数据
- 避免内存抖动
 
- 节制使用
- 排查方法
    - MAT
        - Histogram, 可以列出内存中每个对象的名字, 数量和大小
- Dominator Tree会将所有内存中的对象按大小进行排序, 帮助分析对象直接的引用结构
- Incoming Reference: 对象A它被谁引用, 列举引用引用对象A的引用
- Outgoing Reference: 对象A它引用谁, 列举A对象引用
- 排查: 1). 对着想查看的对象点击右键 -> Lists objects -> with incoming references 2). 右键 -> Path To GC Roots -> exclude weak reference
 
- leakcanary
 
- MAT
        
- Bitmap内存
    - Bitmap复用: 1). 使用LruCache或DiskLruCache做内存或磁盘缓存; 2). 使用Bitmap复用, 使用inBitmap属性
- Bitmap压缩: 1). Bitmap#compress(), 只压缩大小, 不影响内存大小, 2).BitmapFactory.Options.inSampleSize
 
- Bitmap复用: 1). 使用
卡顿
- 常见卡顿
    - UI线程耗时操作, 如UI线程的I/O读写, 数据库访问等
- 复杂不合理的布局和OverDraw
- 内存泄露/抖动导致的卡顿
- 错误的异步方式
 
- 排查方法
    - StrictMode
- TraceView
- AndroidPerformanceMonitor, ANR-WatchDog, Matrix
 
- 优化策略
    - 将UI耗时放到异步
- 合理优化布局, 避免OverDraw
- 优化内存使用
- 正确使用异步
 
ANR
- ANR类型
    - KeyDispatchTimeout, 5S无响应
- BroadcastTimeout, 10秒无响应
- ServiceTimeout, 20秒无响应
- ContentProviderTimeout, 10秒无响应
 
- 常见ANR
    - 主线程阻塞, IOWait, 死锁
- IPC通信, 对端长时间无响应
- 其它线程CPU占用率高
 
- 排查方法
    - trace.txt+ logcat
- dumpsys dropbox
 
网络优化
- 优化策略
    - GZIP压缩(减少流量消耗, 减少传输时间)
- IP直连与HttpDns(解决DNS解析慢和解析失败的问题)
- 图片处理, 1). 图片下载, 使用WebP, 对比JPG, 流量减少25%-35%, 对比PNG能减少80%, 且图片质量未下降, 2). 图片上传
- 协议优化, Http1.1引入持久连接, 多请求复用等, http2引入多工, 头信息压缩, 服务器推送等
- 请求打包, 合并网络请求, 减少请求次数
- 网络缓存
- 断点续传, protocol buffer
 
电量
- 排查
    - 注册广播, 与BatteryManager交互
- Battery Historian, 先通过adb导出电量信息, adb shell dumpsys batterystats --reset
 
- 注册广播, 与
APK瘦身
- 排查
    - Android Studio Analyse APK
- ClassShark
- Nimbledroid
 
- 优化策略
    - 代码层面: 1). 移除无用代码, 功能, 2). 移除无用的库, 避免功能雷同的库, 3). 启动混淆, 4). 缩减方法数
- 资源层面: 1). 移除无用的资源文件, 2). drawable目录只保留一份资源, 3). 对图片压缩, 4). 使用WebP, 5). 资源混淆
- SO层面: 1). 针对用户机型分部保留特定架构的so
- dex中优化debug items字段
 
