Traces de pile dans Compose

Jetpack Compose exécute votre code en plusieurs phases, ce qui entraîne l'exécution de certaines parties de la fonction @Composable séparément les unes des autres. Les plantages au cours de ces phases peuvent entraîner des traces de la pile difficiles à déchiffrer, ce qui complique l'identification de la fonction ou de la ligne de code exacte à l'origine du plantage.

Ajouter des informations sur la source aux traces de la pile

Pour améliorer la lisibilité de la trace de la pile, une API d'activation fournit des informations plus détaillées sur l'emplacement du plantage, y compris les noms et les emplacements des composables. Vous pouvez ainsi :

  • Identifier et résoudre efficacement les sources de plantage
  • Isoler les plantages pour obtenir des exemples reproductibles
  • Examiner les plantages qui n'affichaient auparavant que des blocs de pile internes

L'environnement d'exécution Compose peut détecter l'emplacement du plantage dans la composition et reconstruire une trace de la pile en fonction de votre hiérarchie @Composable. La trace de la pile est ajoutée pour les plantages dans :

  • Composition
  • DisposableEffect et LaunchedEffect (sauf pour onDispose ou annulation)
  • Coroutines lancées dans rememberCoroutineScope
  • Passes de mesure, de mise en page et de dessin

Pour activer cette fonctionnalité, ajoutez les lignes suivantes au point d'entrée de l'application :

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

Idéalement, effectuez cette configuration avant de créer des compositions pour vérifier que les informations de trace de la pile sont collectées correctement.

Il existe quatre options pour ComposeStackTraceMode :

  • Auto : option recommandée, car elle utilise GroupKeys si l'application est minimisée et None dans le cas contraire.
  • GroupKeys : des traces de la pile sont créées pour les applications minimisées. Les informations de clé de groupe sont conservées même après la minimisation. Elles sont utilisées avec le fichier de mappage ProGuard émis par le compilateur Compose et R8 pour reconstruire un emplacement approximatif des fonctions @Composable. Ces traces de la pile sont moins précises et optimisées pour éviter d'effectuer des tâches supplémentaires au moment de l'exécution. Le compilateur Compose est compatible avec l'émission de mappages R8 supplémentaires à partir de Kotlin 2.3.0.
  • SourceInformation : utile pour les builds non minimisés, collecte les informations sources et les ajoute à la trace de la pile. Les résultats sont plus précis, mais entraînent un coût de performances important, semblable à l'association de l'outil d'inspection de la mise en page. Ils sont créés pour être utilisés dans les versions de débogage des applications afin d'obtenir des informations précises sur un plantage qui nécessite plus d'informations sur son emplacement. Les informations sources sont supprimées des applications minimisées pour optimiser la taille et les performances du binaire.
  • None : aucun détail supplémentaire sur la trace de la pile n'est ajouté.

Lorsque vous utilisez l'option SourceInformation, la trace de la pile apparaît sous la forme d'un DiagnosticComposeException dans la liste des exceptions supprimées :

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)

Limites connues

Il existe quelques problèmes connus liés aux frames de trace de la pile :

Traces de la pile des informations sur la source

Numéros de ligne manquants (<unknown line>) dans le premier bloc de pile pour les plantages dans la composition. Étant donné que l'introspection des informations sources se produit après un plantage, les données de la table d'emplacements peuvent être incomplètes et supprimer le numéro de ligne. ReusableComposeNode et remember ne produisent pas d'informations sur la source. Vous verrez donc <unknown line> dans les blocs de pile de ces fonctions.

Traces de la pile des clés de groupe

Les traces de la pile basées sur GroupKeys ne peuvent pointer que vers la première ligne de la fonction @Composable par conception. Ils ne contiennent pas non plus de données pour les fonctions qui ne produisent pas de groupe (telles que les fonctions inline ou qui ne renvoient pas d'unité).

Plantages de la collecte de traces de la pile

Si la collecte de la trace de la pile plante pour une raison quelconque, cette exception est ajoutée en tant qu'exception supprimée au lieu de DiagnosticComposeException.

Signalez tout plantage supprimé ou toute incohérence de trace de la pile au composant d'exécution Compose.