Compose 中的堆栈轨迹

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

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

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

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

Compose 运行时可以检测组合中的崩溃位置,并根据您的 @Composable 层次结构重建堆栈轨迹。针对以下方面的崩溃附加了堆栈轨迹:

  • 组合
  • DisposableEffectLaunchedEffectonDispose 或取消除外)
  • 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>)。由于源信息自省是在崩溃后发生的,因此 slot 表数据可能不完整,并且会丢弃行号。ReusableComposeNoderemember 不会生成源代码信息,因此您会在这些函数的堆栈帧中看到 <unknown line>

组密钥堆栈轨迹

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

堆栈轨迹收集崩溃

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

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