Stack traces in Compose

Jetpack Compose führt Ihren Code in mehreren verschiedenen Phasen aus, wodurch einige Teile der @Composable-Funktion separat voneinander ausgeführt werden. Abstürze in diesen Phasen können zu schwer nachvollziehbaren Stacktraces führen, sodass es schwierig ist, die genaue Funktion oder Codezeile zu ermitteln, die den Absturz verursacht hat.

Quellinformationen zu Stacktraces hinzufügen

Um die Lesbarkeit von Stacktraces zu verbessern, bietet eine Opt-in-API detailliertere Informationen zum Absturzort, einschließlich Namen und Speicherorten von Composables. So können Sie:

  • Absturzursachen effizient identifizieren und beheben
  • Abstürze für reproduzierbare Beispiele isolieren
  • Abstürze untersuchen, bei denen zuvor nur interne Stackframes angezeigt wurden

Die Compose-Laufzeit kann den Absturzort in der Komposition erkennen und einen Stacktrace basierend auf Ihrer @Composable-Hierarchie rekonstruieren. Der Stacktrace wird bei Abstürzen in folgenden Bereichen angehängt:

  • Komposition
  • DisposableEffect und LaunchedEffect (mit Ausnahme von onDispose oder Kündigung)
  • In rememberCoroutineScope gestartete Coroutinen
  • Passen messen, anordnen und zeichnen

Fügen Sie die folgenden Zeilen in den Einstiegspunkt der Anwendung ein, um diese Funktion zu aktivieren:

// 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)
    }
}

Idealerweise führen Sie diese Konfiguration aus, bevor Sie Kompositionen erstellen, um zu prüfen, ob die Informationen zum Stacktrace richtig erfasst werden.

Für die ComposeStackTraceMode gibt es vier Optionen:

  • Auto: Empfohlene Option, da GroupKeys verwendet wird, wenn die App minimiert ist, und None andernfalls.
  • GroupKeys: Stacktraces werden für minimierte Apps erstellt. Die Informationen zum Gruppenschlüssel bleiben auch nach der Minimierung erhalten und werden zusammen mit der ProGuard-Zuordnungsdatei, die vom Compose-Compiler und R8 ausgegeben wird, verwendet, um eine ungefähre Position von @Composable-Funktionen zu rekonstruieren. Diese Stacktraces sind weniger präzise und darauf optimiert, zusätzliche Arbeit zur Laufzeit zu vermeiden. Der Compose-Compiler unterstützt ab Kotlin 2.3.0 die Ausgabe zusätzlicher R8-Mappings.
  • SourceInformation: Nützlich für nicht minimierte Builds. Erfasst Quellinformationen und fügt sie dem Stacktrace hinzu. Die Ergebnisse sind genauer, verursachen aber einen erheblichen Leistungsaufwand, der dem Anfügen des Layoutinspektors ähnelt. Sie werden für Debug-Versionen der Apps erstellt, um genaue Informationen zu einem Absturz zu erhalten, für den weitere Informationen zum Speicherort erforderlich sind. Die Quellinformationen werden aus minimierten Apps entfernt, um die Binärgröße und die Leistung zu optimieren.
  • None: Es wurden keine zusätzlichen Stacktrace-Details hinzugefügt.

Wenn Sie die Option SourceInformation verwenden, wird der Stacktrace als DiagnosticComposeException in der Liste der unterdrückten Ausnahmen angezeigt:

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)

Bekannte Einschränkungen

Es gibt einige bekannte Probleme mit Stacktrace-Frames:

Stacktraces mit Quellinformationen

Fehlende Zeilennummern (<unknown line>) im ersten Stackframe für Abstürze in der Komposition. Da die Quellinformationen erst nach einem Absturz geprüft werden, können die Daten in der Slot-Tabelle unvollständig sein und die Zeilennummer kann fehlen. ReusableComposeNode und remember liefern keine Quellinformationen. Daher wird in den Stackframes für diese Funktionen <unknown line> angezeigt.

Stacktraces für Gruppierungsschlüssel

GroupKeys-basierte Stacktraces können nur auf die erste Zeile der @Composable-Funktion verweisen. Sie enthalten auch keine Daten für Funktionen, die keine Gruppe erzeugen, z. B. Inline- oder nicht einheitenbezogene Funktionen.

Abstürze beim Erfassen von Stacktraces

Wenn die Erfassung des Stack-Trace aus irgendeinem Grund abstürzt, wird diese Ausnahme als unterdrückte Ausnahme anstelle von DiagnosticComposeException angehängt.

Melden Sie alle unterdrückten Abstürze oder Inkonsistenzen im Stacktrace in der Compose-Laufzeitkomponente.