Analisi dello stack in Compose

Jetpack Compose esegue il codice in più fasi diverse, il che fa sì che alcune parti della funzione @Composable vengano eseguite separatamente l'una dall'altra. Gli arresti anomali in queste fasi possono generare analisi dello stack difficili da decifrare, rendendo difficile individuare la funzione o la riga di codice esatta che ha causato l'arresto anomalo.

Aggiungere informazioni sull'origine agli stack trace

Per migliorare la leggibilità dello stack trace, un'API di attivazione fornisce dettagli più ricchi sulla posizione dell'arresto anomalo, inclusi nomi e posizioni dei componenti, consentendoti di:

  • Identificare e risolvere in modo efficiente le origini degli arresti anomali
  • Isola gli arresti anomali per campioni riproducibili
  • Indaga sugli arresti anomali che in precedenza mostravano solo frame dello stack interni

Il runtime di Compose può rilevare la posizione dell'arresto anomalo nella composizione e ricostruire una traccia dello stack in base alla gerarchia @Composable. L'analisi dello stack viene aggiunta per gli arresti anomali in:

  • Composizione
  • DisposableEffect e LaunchedEffect (ad eccezione di onDispose o cancellazione)
  • Coroutine lanciate in rememberCoroutineScope
  • Misurare, creare modelli e disegnare passaggi

Per attivare questa funzionalità, aggiungi le seguenti righe al punto di ingresso dell'applicazione:

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

Idealmente, esegui questa configurazione prima di creare qualsiasi composizione per verificare che le informazioni sulla traccia dello stack vengano raccolte correttamente.

Sono disponibili quattro opzioni per ComposeStackTraceMode:

  • Auto: opzione consigliata, in quanto utilizza GroupKeys se l'app è ridotta e None in caso contrario.
  • GroupKeys: vengono create analisi dello stack per le app ridotte. Le informazioni sulla chiave del gruppo vengono conservate anche dopo la minificazione e vengono utilizzate insieme al file di mapping ProGuard emesso dal compilatore Compose e da R8 per ricostruire una posizione approssimativa delle funzioni @Composable. Queste analisi dello stack sono meno precise e ottimizzate per evitare di eseguire ulteriori operazioni in fase di runtime. Il compilatore Compose supporta l'emissione di mapping R8 aggiuntivi a partire da Kotlin 2.3.0.
  • SourceInformation: utile per le build non compresse, raccoglie le informazioni sull'origine e le aggiunge all'analisi dello stack. I risultati sono più accurati, ma comportano un costo significativo in termini di prestazioni, simile a quello dell'allegato dell'ispettore del layout. Sono creati per essere utilizzati nelle versioni di debug delle app per ottenere letture accurate in caso di arresto anomalo che richiede maggiori informazioni sulla sua posizione. Le informazioni sull'origine vengono rimosse dalle app ridotte per ottimizzare le dimensioni e le prestazioni del binario.
  • None: non sono stati aggiunti dettagli aggiuntivi della traccia dello stack.

Quando utilizzi l'opzione SourceInformation, la traccia dello stack viene visualizzata come DiagnosticComposeException nell'elenco delle eccezioni eliminate:

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)

Limitazioni note

Esistono alcuni problemi noti con i frame di stack trace:

Analisi dello stack delle informazioni di origine

Numeri di riga mancanti (<unknown line>) nel primo frame dello stack per gli arresti anomali nella composizione. Poiché l'introspezione delle informazioni sull'origine avviene dopo un arresto anomalo, i dati della tabella degli slot possono essere incompleti e il numero di riga può essere omesso. ReusableComposeNode e remember non producono informazioni sull'origine, quindi vedrai <unknown line> nei frame dello stack per queste funzioni.

Analisi dello stack delle chiavi di gruppo

Per progettazione, le analisi dello stack basate su GroupKeys possono puntare solo alla prima riga della funzione @Composable. Inoltre, non contengono dati per le funzioni che non producono un gruppo (ad esempio le funzioni inline o che non restituiscono un'unità).

Arresti anomali della raccolta dell'analisi dello stack

Se la raccolta dell'analisi dello stack ha un arresto anomalo per qualsiasi motivo, l'eccezione viene aggiunta come eccezione soppressa anziché DiagnosticComposeException.

Segnala eventuali arresti anomali o incoerenze della traccia dello stack soppressi al componente Compose Runtime.