在应用启动期间,您的应用会给用户留下第一印象。应用启动必须快速加载并显示用户使用应用所需的信息。如果您的应用启动时间过长,用户可能会因为等待时间过长而退出应用。
我们建议使用 Macrobenchmark 库来测量启动时间。该库提供概览和详细的系统跟踪,以准确了解启动期间发生的情况。
系统跟踪提供有关设备上发生情况的有用信息,这有助于您了解应用在启动期间执行的操作,并找出潜在的优化区域。
要分析您的应用启动,请执行以下操作:
- 设置环境以记录应用启动跟踪。
- 了解系统跟踪。
- 使用 Android Studio Profiler 或 Perfetto 浏览跟踪报告。
分析和优化启动的步骤
应用在启动期间通常需要加载对最终用户至关重要的特定资源。非必要的资源可以等到启动完成后再加载。
要权衡性能,请考虑以下因素:
使用 Macrobenchmark 库测量每个操作所花费的时间,并找出耗时较长的代码块。
确认资源密集型操作对于应用启动至关重要。如果操作可以等到应用完全绘制后再执行,则有助于最大限度地减少启动时的资源限制。
确保您预期此操作在应用启动时运行。通常,不必要的操作系统可能会从旧版代码或第三方库中调用。
如果可能,将耗时较长的操作移至后台。后台进程仍会影响启动期间的 CPU 使用率。
在您充分调查该操作后,您可以决定加载时间和将其包含在应用启动中的必要性之间的权衡。请记住,在更改应用工作流时,要考虑可能出现的回归或破坏性更改。
优化并重新测量,直到您对应用的启动时间感到满意。有关详情,请参阅使用指标检测和诊断问题。
测量和分析主要操作中花费的时间
当您获得完整的应用启动跟踪文件后,请查看跟踪文件并测量主要操作(如 bindApplication
或 activityStart
)所花费的时间。我们建议使用 Perfetto 或 Android Studio Profiler 来分析这些跟踪文件。
查看应用启动期间花费的总时间,以确定是否存在以下任何操作:
- 占用大量时间并可以优化。性能方面,每一毫秒都很重要。例如,查找
Choreographer
绘制时间、布局膨胀时间、库加载时间、Binder
事务或资源加载时间。一般来说,请查看所有耗时超过 20 毫秒的操作。 - 阻塞主线程。有关详情,请参阅浏览 Systrace 报告。
- 不需要在启动期间运行。
- 可以等到第一帧绘制完成后。
进一步调查这些跟踪文件,以找出性能瓶颈。
识别主线程上的耗时操作
最佳实践是将文件 I/O 和网络访问等耗时操作放在主线程之外。这在应用启动期间同样重要,因为主线程上的耗时操作会使应用无响应并延迟其他关键操作。StrictMode.ThreadPolicy
可以帮助识别主线程上发生耗时操作的情况。最好在调试版本上启用 StrictMode
以尽早发现问题,如以下示例所示:
Kotlin
class MyApplication : Application() { override fun onCreate() { super.onCreate() ... if (BuildConfig.DEBUG) StrictMode.setThreadPolicy( StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyDeath() .build() ) ... } }
Java
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); ... if(BuildConfig.DEBUG) { StrictMode.setThreadPolicy( new StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyDeath() .build() ); } ... } }
使用 StrictMode.ThreadPolicy
会在所有调试版本上启用线程策略,并在检测到违反线程策略时使应用崩溃,从而难以错过线程策略违规。
TTID 和 TTFD
要查看应用生成其第一帧所需的时间,请测量初始显示时间 (TTID)。但是,此指标不一定反映用户可以开始与应用交互的时间。完全显示时间 (TTFD) 指标在测量和优化实现完全可用应用状态所需的代码路径方面更有用。
有关报告应用界面完全绘制时间的策略,请参阅提高启动时间准确性。
同时优化 TTID 和 TTFD,因为它们在各自的领域都很重要。较短的 TTID 有助于用户看到应用实际正在启动。保持 TTFD 较短很重要,有助于确保用户可以快速开始与应用交互。
分析整体线程状态
选择应用启动时间并查看整体线程切片。主线程需要始终保持响应。
诸如 Android Studio Profiler 和 Perfetto 等工具提供主线程的详细概览以及每个阶段所花费的时间。有关可视化 Perfetto 跟踪的更多信息,请参阅 Perfetto UI 文档。
识别主线程睡眠状态的主要块
如果花费大量时间处于睡眠状态,这很可能是因为应用的主线程正在等待工作完成。如果您有多线程应用,请确定主线程正在等待的线程,并考虑优化这些操作。确保关键路径中没有不必要的锁争用导致延迟也很有用。
减少主线程阻塞和不可中断睡眠
查找主线程进入阻塞状态的每个实例。Perfetto 和 Studio Profiler 会在线程状态时间线上用橙色指示器显示这一点。识别操作,探索这些操作是否符合预期或可以避免,并在必要时进行优化。
与 I/O 相关的可中断睡眠是改进的绝佳机会。其他进程执行 I/O(即使它们是不相关的应用)也可能与顶部应用正在执行的 I/O 发生争用。
缩短启动时间
在您确定优化机会后,探索可能的解决方案以帮助缩短启动时间:
- 延迟和异步加载内容以加快 TTID。
- 尽量减少调用 Binder 调用的函数。如果不可避免,请通过缓存值而不是重复调用或将非阻塞工作移动到后台线程来优化这些调用。
- 为了使您的应用启动看起来更快,您可以在屏幕的其余部分加载完成之前,尽快向用户显示一些需要最少渲染的内容。
- 创建并向您的应用添加启动配置文件。
- 使用 Jetpack App Startup 库在应用启动期间简化组件的初始化。
分析界面性能
应用启动包括启动画面和主页的加载时间。为了优化应用启动,请检查跟踪文件以了解界面绘制所需的时间。
限制初始化工作
某些帧可能比其他帧需要更长的时间才能加载。这些被认为是应用的耗时绘制。
要优化初始化,请执行以下操作:
- 优先处理慢速布局传递,并选择这些进行改进。
- 通过添加自定义跟踪事件来调查 Perfetto 中的每个警告和 Systrace 中的警报,以减少耗时绘制和延迟。
测量帧数据
有多种方法可以测量帧数据。五种主要收集方法是:
- 使用
dumpsys gfxinfo
进行本地收集: dumpsys 数据中观察到的所有帧都不负责应用的缓慢渲染,也不会对最终用户产生任何影响。但是,这是在不同发布周期中衡量以了解性能总体趋势的良好指标。要了解有关使用gfxinfo
和framestats
将界面性能测量集成到您的测试实践中的更多信息,请参阅测试 Android 应用的基础知识。 - 使用 JankStats 进行字段收集: 使用 JankStats 库从应用的特定部分收集帧渲染时间,并记录和分析数据。
- 在 Macrobenchmark (Perfetto 内部) 的测试中
- Perfetto FrameTimeline: 在 Android 12(API 级别 31)上,您可以从 Perfetto 跟踪中收集 帧时间轴指标,以了解是什么工作导致了帧丢失。这可能是诊断帧丢失原因的第一步。
- 用于卡顿检测的 Android Studio Profiler
检查主 Activity 加载时间
应用的主 Activity 可能包含大量从多个来源加载的信息。检查主 Activity
布局,并特别查看主 Activity 的 Choreographer.onDraw
方法。
- 使用
reportFullyDrawn
向系统报告您的应用已完全绘制,以用于优化目的。 - 使用带有 Macrobenchmark 库的
StartupTimingMetric
测量 Activity 和应用启动。 - 查看掉帧。
- 识别渲染或测量时间较长的布局。
- 识别加载时间较长的素材资源。
- 识别启动期间膨胀的不必要布局。
考虑以下可能的解决方案以优化主 Activity 加载时间:
- 使您的初始布局尽可能简单。有关详情,请参阅优化布局层次结构。
- 添加自定义跟踪点以提供有关掉帧和复杂布局的更多信息。
- 最大限度地减少启动期间加载的位图资源的数量和大小。
在布局不立即
VISIBLE
的情况下使用ViewStub
。ViewStub
是一个不可见、大小为零的 View,可用于在运行时延迟膨胀布局资源。有关详情,请参阅ViewStub
。如果您正在使用 Jetpack Compose,您可以使用状态来延迟加载某些组件,从而获得与
ViewStub
类似的行为。var shouldLoad by remember {mutableStateOf(false)} if (shouldLoad) { MyComposable() }
通过修改
shouldLoad
,在条件块内加载可组合项。LaunchedEffect(Unit) { shouldLoad = true }
这会触发重新组合,其中包括第一个代码段中条件块内的代码。
为您推荐
- 注意:当 JavaScript 关闭时,会显示链接文本
- 捕获 Macrobenchmark 指标
- 应用性能测量概览 * 冻结帧