【从入门到实用】android启动优化深入解析

今天一如既往,不做标题党,给大家介绍一些可以实用的启动优化方案~

对于android APP来说,启动时间是用户的第一体验,如果启动时间过长,很可能会流失用户,所以启动优化也是我们做性能优化的一个重要方向
本文主要包括以下内容
1.启动优化有哪些优化方向?
2.如何精准测量启动时间?
3.有哪些实用的优化手段?

启动优化有哪些优化方向?

应用有三种启动状态,每种状态都会影响应用向用户显示所需的时间:冷启动、温启动或热启动。在冷启动中,应用从头开始启动。在另外两种状态中,系统需要将后台运行的应用带入前台。
本文所说的启动优化都是指冷启动优化

要优化应用以实现快速启动,了解系统和应用层面的情况以及它们在各个状态中的互动方式很有帮助。

冷启动

冷启动是指应用从头开始启动:系统进程在冷启动后才创建应用进程。
发生冷启动的情况包括应用自设备启动后或系统终止应用后首次启动。
这种启动给最大限度地减少启动时间带来了最大的挑战,因为系统和应用要做的工作比在另外两种启动状态中更多。

在冷启动开始时,系统有三个任务,它们是:
1.加载并启动应用。
2.在启动后立即显示应用的空白启动窗口。
3.创建应用进程。

系统一创建应用进程,应用进程就负责后续阶段:
1.创建应用对象。
2.启动主线程。
3.创建主 Activity
4.填充视图。
5.布局屏幕。
6.执行初始绘制。

一旦应用进程完成第一次绘制,系统进程就会换掉当前显示的后台窗口,替换为主 Activity。此时,用户可以开始使用应用。

cold-launch.png 如上所示,ApplicationActivity的生命周期就是我们的优化方向
一般为Application onCreate方法与首个Activity加载耗时

如何测量启动时间?

最简单方法

通过查看logcat可以快速了解启动时间
Android Studio Logcat中过滤关键字Displayed,可以看到对应的冷启动耗时日志。

命令测量

for i in seq 1 10
do
adb shell am force-stop com.xx.xx
sleep 2
adb shell am start-activity -W -n 包名/activity名称 | grep “TotalTime” | cut -d ’ ’ -f 2
done

有时候我们需要统计app的冷启动性能,单次结果往往不准确 还需要多次统计以后做平均值
如上,使用脚本启动10次首页Activity,可以比较准确的获取冷启动性能

命令测量方式线下使用方便,可以测试竞品
但是不能带到线上,不能精准控制测量时间
所以我们通常还需要手动埋点

埋点测量

埋点测量关键点在于合适的开始与结束时间
我们一般使用Application attachBaseContext作为开始时间
而启动结束时间则有很多选择

IdleHandler

IdleHandlerMessageQueue空闲时会回调,也就是所在线程任务已经执行完时,线程处于空闲状态时才会执行Idle列表中的任务。
正常情况下,当主线程程处于空闲状态时,可以认为冷启动已经完成,是一个比较不错的打点时机
但有个问题,如果UI线程的任务一直不执行完呢?如果有其他任务加入了MessageQueue但是页面已经可见了呢?
IdleHandler具有一定的不可控特性,读者可根据项目特性判断是否使用

onWindowFocusChanged

Activity回调onWindowFocusChanged时,我们可以认为Activity已经可见了,所以可以在此时打点
不过onWindowFocusChanged 方法只是 Activity 的首帧时间,是 Activity 首次进行绘制的时间,首帧时间和界面完整展示出来还有一段时间差,不能真正代表界面已经展现出来了。

但是onWindowFocusChanged方式与业务耦合少,侵入性低,使用起来比较方便
在我们的项目中回调时间与界面展示时间相差很少,可以作为一种可选方案,根据实际情况使用

onPrewDrawListener

如上面所说,正确的计算启动耗时的时机是要等真实的数据展示出来,比如在列表第一项的展示时再计算启动耗时。
我们可以在给列表的第一项添加onPreDrawListener监听,这种方式比较准确
不过这种方式与业务代码强相关,侵入性较大。读者也可根据实际情况使用

AOP测量方法耗时

我们的Application中初始化了很多第三方库,有时我们需要统计每个方法的耗时,确定是哪个方法比较耗时,如果一个一个添加是很麻烦的
这种时候就可以使用AOP面向切面编程
如果想了解详情,请参阅使用AOP测量方法耗时

TraceView与SystraceView使用

TraceView

TraceView可以跟踪 App 某段时间内所有调用过的方法,这是测量应用执行性能常用的方式之一.
通过它我们可以查出 App 启动时具体都调用了方法,都花了多长时间。
这个功能是 Android 系统提供的,我们可以通过在代码里手动调用 android.os.Debug.startMethodTracing()stopMethodTracing() 方法来开始和结束 Tracing,然后系统会把 Tracing 的结果保存到手机的 .trace 文件里。

此外,除了通过写代码来 Trace,我们也有更方便的方式。例如也可以通过 Android Studio Profiler 里的 Method TracerTrace。但是,针对 App 的冷启动,我们则通常会用 Android 系统自带的 Am 命令来跟踪,因为它能准确的在 App 启动的时候就开始 Trace

启动指定 Activity,并同时进行采样跟踪,-P在app进入idle状态时profiler结束

adb shell am start -n com.xxx.android/com.xxx.android.app.ui.activity.MainActivity -P /data/local/tmp/xxx-startup.trace --sampling 1000

拉取 .trace 文件到本机当前目录

adb pull /data/local/tmp/xx-startup.trace .

如上所示:-P参数表示在app进入idle状态时会自动结束,这样就不必手动打点了
在启动结束后,通过adb pull拉取trace文件后,直接拖到android studio中打开就可以查找耗时方法了

更多关于TraceView定位启动优化问题的实例,读者可参阅:
TraceView使用
知乎 Android 客户端启动优化 - Retrofit 代理

Systrace

TraceView 虽然是找出耗时方法的利器,但是执行 TraceView 时的运行环境和用户最终运行的环境会有极大的差距,因为 TraceView 会严重拖慢 App 的执行速度。
即使使用采样跟踪,测量得到的结果和实际结果肯定还是有很大偏差,只能作为参考。
而且 TraceView 更偏向于追查应用的内因,对于运行环境等外因(锁、GC、资源匮乏等)的追查显得很无力。
所以,我们可以借助另一个 Google 官方极力推荐的工具 - 「Systrace」来跟踪 App 实际运行时的情况

运行app后,手动杀掉。然后cdSDK 目录下的 platform-tools/systrace 下,使用命令:

python systrace.py -t 10 -o /Users/xxx/trace.html -a com.xx.xxx

其中:-t 10是指跟踪10秒,-o 表示把文件输出到指定目录下,-a 是指定应用包名。
输入完这行命令后,可以看到开始跟踪的提示。看到 Starting tracing 后,手动打开我们的应用。

等到运行结束后打开输出的trace.html

除了以上外,我们也可以通过TraceCompact.beginSection来指定关注的时间段
更多关于Systrace使用的实例,读者可以参阅:
systrace使用
知乎 Android 客户端启动优化 - Retrofit 代理-Systrace

小结

1.TraceView可以用来定位具体耗时的方法
2.TraceView运行时开销严重,导致整体性能变慢,可能会带偏优化方向
3.Systrace开销小,可以直观反映Cpu使用率,便于查找运行环境等外因(锁,GC)等引起的问题
4.TraceViewSystrace都可以埋点,指定关心的区域

常规优化手段

1.Theme切换

Theme设置可以说是启动优化的一个必备手段了
启动ActivitywindowBackground主题属性预先设置一个启动图片(layer-list实现),在启动后,在ActivityonCreate()方法中的super.onCreate()前再setTheme(R.style.AppTheme)

优点
1.使用简单。
2.避免了启动白屏和点击启动图标不响应的情况。

缺点
治标不治本,表面上产生一种快的感觉。

2.异步方案

我们通常会在ApplicationonCreate中初始化很多任务,比如第三方库初始化,而且是串行的
这些初始化任务的耗时通常还不小,所以一个优化思路就是并行的初始化
这样就将初始化耗时从加法变成了求最大值

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

常规异步方案的问题

1.代码不够优雅
假如我们有 100 个初始化任务,那我们就需要提交 100 次任务。

2.无法限制在 onCreate 中完成
有的第三方库的初始化任务需要在 ApplicationonCreate 方法中执行完成,虽然可以用 CountDownLatch 实现等待,但是还是有点繁琐。

3.无法实现存在依赖关系
有的初始化任务之间存在依赖关系,比如极光推送需要设备ID,而 initDeviceId() 这个方法也是一个初始化任务。

异步启动器方案

上面介绍了常规异步方案的几个问题,我们可以通过启动器来解决
启动器的核心思想是充分利用多核 CPU ,自动梳理任务顺序。

1.第一步是我们要对代码进行任务化,任务化是一个简称,比如把启动逻辑抽象成一个任务。

2.第二步是根据所有任务的依赖关系排序生成一个有向无环图,这个图是自动生成的,也就是对所有任务进行排序。
比如我们有个任务 A 和任务 B,任务 B 执行前需要任务 A 执行完,这样才能拿到特定的数据,比如上面提到的 initDeviceId

3.第三步是多线程根据排序后的优先级依次执行,比如我们现在有三个任务 ABC。 假如任务 B 依赖于任务 A,这时候生成的有向无环图就是 ACBAC 可以提前执行,B 一定要排在 A 之后执行。

启动器的大致流程如上所示,我们下面介绍几种开源的启动器方案,供读者参考

JetPack App Startup

1.App Startup 这个库提供了一个组件,可以在应用程序启动的时候初始化。
2.开发人员可以使用这个组件精简启动序列和显式地设置初始化的顺序。  
3.我们不需要为每个组件定义单独的 ContentProvider,App Startup 允许您定义的所有组件化共享一个内容提供者。

这样可以极大地减少高应用程序的启动时间,但是App Startup只是支持将多个ContentProvider合并到一个ContentProvider中,并指定一定依赖顺序
它的推出的目的,是管理第三方库使用ContentProvider过多,导致启动速度变慢的问题
不支持异步与异步任务管理,所以并不符合我们的要求

阿里-alpha

Alpha是一个基于PERT图构建的Android异步启动框架,它简单,高效,功能完善。 在应用启动的时候,我们通常会有很多工作需要做,为了提高启动速度,我们会尽可能让这些工作并发进行。但这些工作之间可能存在前后依赖的关系,所以我们又需要想办法保证他们执行顺序的正确性。Alpha就是为此而设计的,使用者只需定义好自己的task,并描述它依赖的task,将它添加到Project中。框架会自动并发有序地执行这些task,并将执行的结果抛出来。 由于Android应用支持多进程,所以Alpha支持为不同进程配置不同的启动模式。

alpha已经基本满足我们的使用,不过它不支持任务是否需要等待,同时它的代码比较旧,感觉已经很久不维护了,所以最后决定使用AnchorTask框架

AnchorTask

AnchorTask与Alpha类似
1.支持多任务并发执行
2.支持任务间依赖与拓扑排序
3.支持任务监听与耗时统计

结语

  • 现在随着短视频,抖音,快手的流行NDK模块开发也显得越发重要,需要这块人才的企业也越来越多,随之学习这块的人也变多了,音视频的开发,往往是比较难的,而这个比较难的技术就是NDK里面的技术。
  • 音视频/高清大图片/人工智能/直播/抖音等等这年与用户最紧密,与我们生活最相关的技术一直都在寻找最终的技术落地平台,以前是windows系统,而现在则是移动系统了,移动系统中又是以Android占比绝大部分为前提,所以AndroidNDK技术已经是我们必备技能了。
  • 要学习好NDK,其中的关于C/C++,jni,Linux基础都是需要学习的,除此之外,音视频的编解码技术,流媒体协议,ffmpeg这些都是音视频开发必备技能,而且
  • OpenCV/OpenGl/这些又是图像处理必备知识,下面这些我都是当年自己搜集的资料和做的一些图,因为当年我就感觉视频这块会是一个大的趋势。所以提前做了一些准备。现在拿出来分享给大家。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值