Please enable Javascript to view the contents

Android性能优化

 ·  ☕ 6 分钟  ·  🎅 qqnv
    🏷️

为什么要做性能优化

  1. 体验差影响核心指标
  2. 线上问题追查困难
  3. 降低性能优化的长期开销

介绍性能平台

  1. 交代背景
  2. 具体讲解

为什么要自建APM

  1. 需求层面(APP启动时间,可以分为Application、Activity耗时商业APM不满足需求)
  2. 效率层面
  3. 数据安全

平台化

  1. crash管理平台(bugly:数据采集上报成功率高,包含java和native崩溃)
  2. 商业级APM平台(听云:通用性能解决方案数据采集完善,方便接入但不满足个性化要求数据存在隐患)
  3. 自建APM(美团、携程:贴合自身业务特点满足定制化需求,数据安全)

APP启动优化

冷启动

耗时最多,衡量标准

  1. Click Event 用户点击事件
  2. IPC 触发IPC操作
  3. Process.start 进程创建
  4. ActivityThread 单独进程APP的入口类,消息和handler的相关创建
  5. bindApplication 通过反射创建Application调用与之相关的生命周期
  6. LifeCycle Activity生命周期
  7. ViewRootImpl 界面绘制

冷启动之前,系统的行为

  • 启动App
  • 加载空白window
  • 创建进程

随后任务

  • 创建Application
  • 启动主线程
  • 创建Activity
  • 加载布局
  • 布置屏幕
  • 首帧绘制

热启动

最快

  1. 后台
  2. 前台

温启动

较快

  1. LifeCycle Activity生命周期

启动时间测量方式

adb命令

方法:adb shell am start -W packagename/首屏Activity

  • ThisTime:最后一个Activity启动耗时
  • TotalTime:所有Activity启动耗时
  • WaitTime:AMS启动Activity的总耗时

优缺点:线下使用方便,不能带到线上。非严谨、精确时间

手动打点

启动时埋点,启动结束埋点,二者差值

注意:

  • 误解:onWindowFocusChanged只是首帧时间,不算启动结束
  • 正解:真实数据展示,Feed第一条展示(addOnPreDrawListener)
  • 启动的时间写在Application中的attachBaseContext方法中

优点:精确,可带到线上,推荐使用

启动优化工具选择

traceview

  • 图形的形式展示执行时间、调用栈等
  • 信息全面,包含所有线程

使用方式

  • ‘Debug.startMethodTracing()’
  • ‘Debug.stopMethodTracing()’
  • 生成文件在sd卡:Android/data/packagename/files

优缺点:

  • 运行时开销严重,整体都会变慢
  • 可能会带偏优化方向
  • traceview与cpu profiler

systrace

  • 结合Android内核的数据,生成Html报告
  • API18以上使用,推荐TraceCompat

使用方式

优缺点:

  • 轻量级,开销小
  • 直观反应cpu利用率
  • cputime与walltime区别(举例:锁冲突)

优雅获取方法耗时

常规方式

手动埋点 (SystemClock.currentThreadTimeMillis())

侵入性强、工作量大

AOP介绍

Aspect Oriented Programming,面向切面编程

  • 针对同一类问题的统一处理
  • 无侵入添加代码

AspectJ使用

  • classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
  • implementation 'org.aspectj:aspectjrt:1.8.+'

Join Points
程序运行时的执行点,可以作为切面的地方

  • 函数调用、执行
  • 获取、设置变量
  • 类初始化

PointCut
带条件的JoinPints

Advice
一种Hook,要插入代码的位置

  • Before: PointCut之前执行
  • After: PointCut之后执行
  • Around: PointCut之前、之后分别执行

语法简介

  • Before: Advice,具体插入位置
  • execution:处理Join Point的类型,call、execution
  • (“execution(android.app.Activity.on*(..))"):匹配规则
  • onActivityCalled:要插入的代码
1
2
3
4
@Before("execution(*android.app.Activity.on**(..))")
public void onActivityCalled(JoinPoint joinPoint) throws Throwable{
  ...
}

AOP实战

实例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Aspect
class PerformanceAop {
    @Around("call(*com.ares.firstcode.MyApplication.**(..)")
    fun getTime(joinPoint: ProceedingJoinPoint){
        val signature = joinPoint.signature
        val name = signature.name
        val time = System.currentTimeMillis()
        try {
            joinPoint.proceed()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        Log.i("","$name cost ${System.currentTimeMillis()-time}")
    }
}

优点:无侵入性修改方便

异步优化

常规优化

核心思想:子线程分担主线程任务,并行减少时间

CountDownLatch解决异步时某些初始化工作必须等待完成后才会初始化完成

注意事项:

  • 不符合异步要求
  • 需要在某阶段完成
  • 区分cpu密集型和io密集型

常规异步痛点:

  • 代码不够优雅
  • 场景不好处理(依赖关系)
  • 维护成本高

启动器优化

核心思想:充分利用CPU多核,自动梳理任务顺序

  • 代码Task化,启动逻辑抽象为Task
  • 根据所有任务依赖关系排序生成一个有向无环图
  • 多线程按照排序后的顺序依次执行

流程图

延迟初始化

常规方案

  • new Handler().postDelayed
  • Feed展示后调用

缺点:时机不便控制、导致Feed卡顿

更优方案

核心思想:对延迟任务进行分批初始化->IdleHandler特性,空闲执行

  • 执行时机明确
  • 缓解Feed卡顿

优化总方针

  • 异步、延迟、懒加载
  • 技术、业务相结合

其它方案

  • 启动阶段抑制GC
  • CPU锁频(会增加耗电量)
  • 提前异步SharedPreferences
  • 启动阶段不启动子进程
  • 提前异步类加载

App内存优化

  • 内存泄漏
  • 内存抖动
  • Bitmap
  • 谨慎使用SharedPrence
  • 谨慎使用外部库
  • 业务架构设计合理

App布局优化

工具

  • Aop、Hook
  • Systrace、layout inspector

优化

  • IO、反射、遍历
  • 异步inflate、x2c、减少层级、重绘
  • Aop、监控

结果产出

  • 体系化监控手段:线下&线上
  • 指标:FPS、加载时间、布局层级

App线程优化

  • 线程收敛
  • 统一线程池:任务区分
  • 其他细节

App网络优化

网络切换、弱网、无网测试

服务端

  • 服务端监控请求耗时(地域、时段、版本、机型)
  • 服务端监控失败率(业务失败、请求失败)
  • 服务端监控Top失败和异常接口

客户端

  • 接口的每一步详细信息(DNS、链接、请求)
  • 请求次数、网络包大小、失败原因
  • 图片监控

异常监控体系

  • 服务器防刷:超限拒绝访问
  • 客户端:大文件预警、异常兜底策略
  • 单点问题追查

App电量优化

CPU时间片

  • 获取运行过程CPU消耗,定位CPU占有率异常方法
  • 减少后台应用主动运行

网络请求

  • 请求时机及次数限制
  • 数据压缩减少时间
  • 避免使用轮询功能

定位相关

  • 根据场景谨慎选择定位模式
  • 考虑网络定位代替GPS
  • 使用后务必及时关闭,减少更新频率

界面相关

  • 离开界面后停止相关活动
  • 耗电操作判断前后台

weaklock相关

  • 注意成对出现:acquire与release
  • 使用带参数的acquire
  • finally确保一定会被释放
  • 常亮场景使用keepScreenOn即可

JobSchedular

  • 在符合某些条件时创建执行在后台的任务
  • 把不紧急的任务放到更合适的时机进行批量处理

App瘦身优化

  • 代码瘦身
    代码混淆:Proguard
    基础库统一,选择更小的库,引入仅需的部分代码

    移除无用代码,AOP统计使用情况

  • 资源瘦身
    自带工具
    图片压缩
    资源混淆:AndResGuard

  • so瘦身
    都放在armeabi目录,根据CPU类型加载对应架构so
    so动态下载或插件化

App稳定性优化

分享

qqnv
作者
qqnv
Android Developer