Compose 中的堆栈轨迹

Jetpack Compose 会在多个不同阶段执行您的代码,这会导致 @Composable 函数的某些部分彼此分开执行。这些阶段发生的崩溃可能会导致堆栈轨迹难以解读,从而难以确定导致崩溃的确切函数或代码行。

向堆栈轨迹添加源代码信息

为了提高堆栈轨迹的可读性,我们提供了一个选择启用的 API,该 API 可提供更丰富的崩溃位置详细信息,包括可组合项名称和位置,使您能够:

  • 高效识别和解决崩溃来源
  • 隔离崩溃以获取可重现的示例
  • 调查之前仅显示内部堆栈帧的崩溃

Compose 运行时可以检测组合中的崩溃位置,并根据 @Composable 层次结构重构堆栈轨迹。对于以下位置发生的崩溃,系统会附加堆栈轨迹:

  • 乐曲
  • DisposableEffect 和 LaunchedEffect(onDispose或取消除外)
  • 在 rememberCoroutineScope 中启动的协程
  • 测量、布局和绘制传递

如需启用此功能,请将以下代码行添加到应用入口点:

// Enable stack traces at application level: onCreate
class SampleStackTracesEnabledApp : Application() {

    override fun onCreate() {
        super.onCreate()
        // Enable Compose stack traces for minified builds only.
        Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.Auto)

        // Alternatively:
        // Enable verbose Compose stack traces for local debugging
        Composer.setDiagnosticStackTraceMode(ComposeStackTraceMode.SourceInformation)
    }
}

理想情况下,请在创建任何组合之前执行此配置,以验证堆栈轨迹信息是否已正确收集。

ComposeStackTraceMode 有四个选项:

  • Auto:推荐选项,因为如果应用经过缩减大小,它会使用 GroupKeys,否则会使用 None。
  • GroupKeys:系统会为缩减大小的应用创建堆栈轨迹。即使在缩减大小后,组键信息也会保留,并与 Compose 编译器和 R8 发出的 ProGuard 映射文件一起使用,以重构 @Composable 函数的大致位置。 这些堆栈轨迹不太精确,经过优化,可避免在运行时执行额外的工作。从 Kotlin 2.3.0 开始,Compose 编译器支持发出额外的 R8 映射。
  • SourceInformation:适用于未缩减大小的 build,可收集源代码信息并将其添加到堆栈轨迹中。结果更准确,但会产生与附加布局检查器类似的显著性能开销。它们旨在用于应用的调试版本,以便准确读取需要更多位置信息的崩溃。系统会从缩减大小的应用中移除源代码信息,以优化二进制文件大小和性能。
  • None:未添加额外的堆栈轨迹详细信息。

使用 SourceInformation 选项时,堆栈轨迹随后会作为 DiagnosticComposeException 显示在被抑制的异常列表中:

java.lang.IllegalStateException: Test layout error
    at <original trace>
Suppressed: androidx.compose.runtime.DiagnosticComposeException:
Composition stack when thrown:
    at ReusableComposeNode(Composables.kt:<unknown line>)
    at Layout(Layout.kt:79)
    at <lambda>(TempErrorsTest.kt:164)
    at <lambda>(BoxWithConstraints.kt:66)
    at ReusableContentHost(Composables.kt:164)
    at <lambda>(SubcomposeLayout.kt:514)
    at SubcomposeLayout(SubcomposeLayout.kt:114)
    at SubcomposeLayout(SubcomposeLayout.kt:80)
    at BoxWithConstraints(BoxWithConstraints.kt:64)
    at SubcomposeLayoutErrorComposable(TempErrorsTest.kt:164)
    at <lambda>(TempErrorsTest.kt:86)
    at Content(ComposeView.android.kt:430)
    at <lambda>(ComposeView.android.kt:249)
    at CompositionLocalProvider(CompositionLocal.kt:364)
    at ProvideCommonCompositionLocals(CompositionLocals.kt:193)
    at <lambda>(AndroidCompositionLocals.android.kt:113)
    at CompositionLocalProvider(CompositionLocal.kt:364)
    at ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:102)
    at <lambda>(Wrapper.android.kt:141)
    at CompositionLocalProvider(CompositionLocal.kt:384)
    at <lambda>(Wrapper.android.kt:140)

已知限制

堆栈轨迹帧存在一些已知问题:

来源信息堆栈轨迹

在组合中发生崩溃时,第一个堆栈帧中缺少行号 (<unknown line>)。由于源代码信息自省是在崩溃后进行的,因此槽表数据可能不完整,并且会丢弃行号。 ReusableComposeNode 和 remember 不会生成源代码信息,因此您会在这些函数的堆栈帧中看到 <unknown line>。

分组键堆栈轨迹

根据设计,基于 GroupKeys 的堆栈轨迹只能指向 @Composable 函数的第一行。它们也不包含任何不生成组的函数(例如内嵌函数或不返回 Unit 的函数)的数据

堆栈轨迹收集崩溃

如果堆栈轨迹收集因任何原因而崩溃,则该异常会作为被抑制的异常(而不是 DiagnosticComposeException)附加。

向 Compose 运行时组件报告任何被抑制的崩溃或堆栈轨迹不一致问题。