如何改善应用启动性能 | Facebook应用的经验分享

11124ffe68d4c7cb364868d274ccc22c.png

/   今日科技快讯   /

近日,持续8个月之久的长短视频之争有了新进展。腾讯向法院申请变更诉讼请求,将《斗罗大陆》索赔金额从6160万元提高到8亿元。至此,腾讯半年来起诉抖音的标的总额已超过29.43亿元。2021年6月初,腾讯在重庆市第一中级人民法院为《斗罗大陆》动漫申请了诉前行为保全,认为抖音平台内的用户上传内容侵害了《斗罗大陆》著作权。腾讯要求抖音立即删除所有侵权视频,立即采取有效措施过滤、拦截用户上传及传播的侵权视频。在未经实质审理的情况下,法院于收到行为保全申请的两天后作出裁定,支持了腾讯的请求。

/   简介   /

缩短应用的启动时间并非小事,我们必须深入了解其影响因素。今年,Google Android 团队和 Facebook 应用团队一直在合作研究这方面的量化指标,并共享优化方法,以改善应用启动情况。Google Android 的公开文档中包含了很多关于 应用启动优化的信息。这里我们想进一步分享其在 Facebook 应用中的实践情况,以及哪些因素有助于改善应用启动性能。

https://developer.android.google.cn/topic/performance/vitals/launch-time

现在,每个月有超过29亿人使用Facebook。Facebook帮助人们构建社区,并让世界更紧密地联系在一起。用户会在这里分享生活的瞬间,了解和讨论正在发生的事情,建立和培养人际关系,共同合作以创造收入机会。

Facebook应用开发者则致力于确保用户享受最佳体验,并让应用在任意设备、任何国家/地区和不同网络条件下都能流畅运行。Google Android团队和Facebook团队精诚合作,在应用启动时间的指标定义和最佳实践上达成共识,并在这里分享给大家。

/   从哪里开始   /

首先自然是测量应用的启动时间。您可借此获悉用户启动体验的健康程度,追踪启动时间恶化的情况,并计算进行改进需要投入的资源量。归根结底,您的启动时间需要与用户满意度、参与度或用户增长相关联,以确定投入的优先次序。

Android定义了两个衡量应用启动时间的指标:完全显示所用时间 (TTFD) 和初步显示所用时间(TTID)。

虽然您可以进一步将其划分为冷/暖启动时间,但本文不会解释它们之间的区别,而 Facebook 的方法是,衡量和优化与应用交互的所有用户所经历的启动时间 (有些是冷启动,有些是暖启动)。

完全显示所用时间 (Time-To-Full-Display, TTFD)

TTFD会记录您的应用完成渲染并可供用户交互和使用时所需的时间,可能包括显示本地存储或来自网络上的内容所需的时间。如果网络较慢,这可能会花费一段时间,并会视用户的使用设备而有所差异。因此,我们有必要立即展示一些内容,让用户看到应用启动的进程,而这就要提到TTID了……

初步显示所用时间 (Time-To-Initial-Display, TTID)

TTID会记录您的应用显示背景、导航、可快速加载的本地内容、加载较慢的本地或网络内容的占位块所需要的时间。TTID应该是用户可以四处导航并前往其目标的所需时间。

不要改变太多:有一件事需要注意,就是在TTID和TTFD之间应用内容的视觉变化问题,例如在页面里先展示的是已缓存的内容,然后在网络内容加载完成后突然切换页面内容。这种突然的变化可能会让用户感到不快和沮丧,所以请确保您的应用可在TTID期间显示足够有意义的内容,尽可能地向用户展示其将在TTFD期间看到的内容。

/   达成用户目标   /

用户访问您的应用是为了获取内容,这可能需要一段时间完成加载,而您希望应用可以尽快把这些内容呈现给他们。

Facebook 应用开发者专注于基于 完全显示所用时间 (TTFD) 的指标,包含显示所有内容和图像,因为这代表了用户访问应用的完整体验。开发者想要知道,网络加载内容和图像是否花费了较长时间,或者加载失败,以便让团队可以从头到尾改善整个启动体验。

/   良好的TTID和TTFD目标应当是多少?   /

Facebook将启动时间指标设定为他们认为应用启动耗时“不佳”的百分比,即任何TTFD超过2.5秒的启动或启动失败的部分 (例如,图像无法加载或应用崩溃)。Facebook致力于通过改进时间超过2.5秒的启动,使其摆脱“不佳”状态,以及修复导致启动失败的问题,从而降低启动时间“不佳”的比例。选择 2.5 秒是因为,研究表明,这对于Facebook用户来说很重要。这也与Web Vitals为网站建议的最大内容绘制(LCP)指标相符。

与TTID相比,提供完整体验,尤其是用网络获取最近的内容,会让您的TTFD启动指标看起来相当缓慢。而这其实是一件好事!它反映了用户对您应用的真实体验。您对此所做的改进,可能会像Facebook那样,提高用户的应用使用率以及对其性能的认可。

测量TTFD的棘手程度可能会视您的应用而异。如果太难,不妨从 初步显示所用时间(TTID)着手。虽然由于占位块或图像的存在可能会导致无法量化部分内容的加载性能,但这依然是一个着手点,毕竟这部分也是用户日常与应用交互的内容 (虽然不是全部)。

/   检测TTID   /

在 Android 4.4 (API 级别 19)及更高版本中,logcat提供了"Displayed"值,用于记录从启动进程到完成在屏幕上绘制相应Activity第一帧所经过的时间。报告的日志行类似于以下示例:

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

/   检测TTFD   /

要检测TTFD,只需在您的所有内容都在屏幕上显示后,在Activity中调用reportFullyDrawn()。

请确保包含替换占位符的任何内容,以及您渲染的任何图像(务必计算图像本身显示的时间,而不仅是其占位符显示的时间)。在您调用reportFullyDrawn()后,就可以在logcat里看到它:

ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms

/   来自Facebook应用开发者的建议   /

多年来,Facebook应用开发者一直在为众多设备、平台以及国家/地区的数十亿用户优化应用。本节分享了Facebook应用开发者在优化应用启动时运用的一些关键经验。

先理解,再优化 - 在定义了好的启动指标后,您就应该用其检测应用的具体表现,这有助于理解应用的启动性能并设置改进优先级,为您的用户带来更好的体验。从量化检测入手,一来可以证明存在提升空间,二来可以确定重点努力的方向,并且在开始优化后能看到具体的改进效果。

首先修复崩溃 - 在您检测启动状况之后,请确保应用确实可以启动。启动时的崩溃是最让人沮丧的事情,也是让用户放弃您应用的最快方式,请优先判定和处理这些问题。

切莫忘记功能可靠性 - 另外,不要忘记功能可靠性。您的应用是否能迅速展示一些内容,但却未能加载所有内容,或者加载图像的耗时过长?您的应用可能启动得很快,但未能按用户要求运行 (比如,点击按钮不起作用),这些因素都会恶化用户体验。

以一致性为目标 - 与具备一致性但启动时间长于平均水平的性能表现相比,不一致的性能表现更令人沮丧。观察启动时间的长尾,查看是否存在缓解这些启动缓慢情况的修复措施或方法。请务必查看您的离线和有损网络启动性能的启动行为。

并行工作 - 大多数当代手机都有至少4个CPU,所以有空间处理多任务!除非万不得已,否则不要阻塞主线程。将I/O和非关键路径移动到主线程之外运行。

延迟执行 - 在实现了可靠且一致的启动后,请查看您为显示首个可见画面的内容所做的一切,是否有一些工作是不必要的?在应用启动之后,请把与启动体验不直接相关的任何工作移除、延后、或者移到后台 (但是注意观察应用的响应能力,并将其作为一个控制指标)。试着让您应用的 onCreate() 尽量保持轻量。您还可使用 Jetpack App Startup 开发库,以便在应用启动时初始化组件。这样做时,请确保仍然加载所有启动活动所需的模块,并且注意在延迟加载的模块可用时不要造成闪烁。

显示进度,但是不要过多地改变界面 - 请不要在启动期间过度改变要展示给用户的内容。如果用户尝试点击内容,结果它却发生变化,并得到了错误的结果,这是十分令人沮丧的。这类似于 Web Vitals 中的 累积布局偏移 (CLS) 概念。对于时长不定的网络端加载,请略过启动画面,并显示异步加载的占位符。您可以考虑在这个内容区域使用不太显眼的 动画 来反映加载状态。确保具体加载的内容结构和占位结构尽可能地匹配,以便在内容加载完成后实现平滑过渡。

缓存 - 当用户第一次打开应用时,您可以为一些界面元素展示加载指示器。在用户下次访问您的应用时,您可在加载更多最新内容的同时,显示这些已缓存的内容。您是否曾在应用加载完成后,看到我们在 Facebook 的动态更新中展示从网络获取到的最新内容?如果可以,请将网络加载过程从启动中排除出去,这样可以加快速度,并实现更一致的启动性能体验。但是,正如下一点所建议的那样,显示已缓存的内容并不总是最佳做法,因此,我们要衡量并找到对用户更友好的要素。

快慢结合 - 新颖,相关,但显示速度稍慢的内容,比快速显示的过时内容更好。直接向您的用户展示最新的内容,比启动超级迅速,但在启动不久之后就得刷新内容要更有价值。您可以评估以下做法是否效果更好: 做出优化,以尽量快速地显示最新内容,并设置超时时间,以在网络较慢时显示较旧的内容;在网络离线时,直接显示既有的内容。

一致的会话开始界面 - 在您的应用长时间处于后台后,您可能会发现,将用户重置到您的主内容界面是很好的做法。应用可以在设备的内存中保留很长时间。

查看内部工作原理 - 如果您 跟踪 并切实查看了启动期间执行的内容,或者干脆使用调试器,您可能会有让人惊喜的新发现!在充分了解了启动的关键路径后,您就可以高效地优化应用性能。在发现了具有最大提升空间的要素后,就在该方面做出投入。

确保能轻松实现正确的结果 - 开发者有时会使用并非最优的模式和架构,因为做事情的方法太多了。请放心大胆地整合您应用中使用的模式,然后加以优化,以便轻松选择合适方法,从而完成任务并让其高效运行。即时代码执行 (eager code execution) 模式就是一个很好的例子: 如果您正在执行第一次全屏绘制后才需要出现的内容代码,那么性能表现肯定会遭受损害。您不妨采用延迟执行的模式,仅在启动的关键路径遭到阻塞时,再以即时执行方式运行代码。

/   Google Android团队给出的建议   /

Google Android 团队关于衡量和优化应用启动的建议请查阅官方文档“应用启动时间”。具体地址如下所示:

https://developer.android.google.cn/topic/performance/vitals/launch-time

本节总结了一些适用于所有Android应用开发者且与上述Facebook建议相关的要点。

TTID和TTFD是应用启动的重要指标。Google Android会在Play管理中心按照TTID对应用进行排名。TTFD是TTID的母集,因此TTID的任何改进措施都同时适用于这两个指标。

调用reportFullyDrawn()来报告TTFD,让系统知道Activity已完成渲染。为改善应用启动速度,Android系统会进行调整,以优先处理在调用reportFullyDrawn()之前发生的工作。在您的应用处于完全可用状态时调用这个方法可以改善应用的启动时间。每个应用都应该使用这个API!切莫忘记用其衡量应用表现情况。

用Android Vitals监控您应用的技术性能,有助于改善应用启动体验。通过Play管理中心,您可以查看各种数据以帮助您了解和改进应用的启动时间等性能表现。

我们知道,与在开发阶段修复错误相比,生产环境中的修复成本要高得多。这点也同样适用于性能方面。您可以借助Jetpack Macrobenchmark: Startup设置您的应用,以在早期使用本地性能测试衡量应用启动情况。

正如我们上面讨论的那样,量化检测是了解和优化启动的关键。Android提供系统跟踪服务,可以帮助深入挖掘和诊断应用启动问题。

通过Jetpack App Startup开发库,我们可以直接高效地在应用启动时初始化组件。开发库和应用的开发者都可以使用此库来简化启动流程,并明确地设置初始化顺序。您可以使用此库设置在启动期间的什么时刻加载哪些组件。

影响应用启动的一个典型问题是在初始化时做了太多工作。比如,填充过大或复杂的布局、阻止屏幕绘制、加载和解码位图、垃圾回收等。

/   总结   /

本文介绍了一些关键的启动时间指标和优化最佳实践,以改善启动体验,帮助提升Facebook Android应用的用户参与度和使用率。本文还分享了Google Android团队建议的指标、开发库和工具。任何Android应用都可从本文分享的策略中受益。请大家动起手来,认真量化应用的启动情况,并为用户打造快速且令人愉悦的应用启动体验!欢迎点击这里:

https://services.google.cn/fb/forms/androiddevswechat2/

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

再看LayoutInflater,这次你可能又会有新的认识

PermissionX 1.5发布,支持申请Android特殊权限啦

欢迎关注我的公众号

学习技术或投稿

30e3d19a53faa701d9f0d1122c699667.png

f2f2332183d494220000474815118fed.png

长按上图,识别图中二维码即可关注

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值