Analisi dello stack in Compose

Jetpack Compose esegue il codice in più fasi diverse, il che comporta l'esecuzione di alcune parti della funzione @Composable 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.

Aggiungi informazioni sull'origine alle analisi dello stack

Per migliorare la leggibilità dell'analisi dello stack, un'API con attivazione fornisce dettagli più completi sulla posizione dell'arresto anomalo, inclusi i nomi e le posizioni dei componibili, consentendoti di:

  • Identifica e risolvi in modo efficiente le cause degli arresti anomali
  • Isola gli arresti anomali per i campioni riproducibili
  • Esamina gli arresti anomali che in precedenza mostravano solo frame di stack interni

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

  • Composizione
  • DisposableEffect e LaunchedEffect (ad eccezione di onDispose o annullamento)
  • Coroutine avviate in rememberCoroutineScope
  • Fasi di misurazione, layout e disegno

Per attivare questa funzionalità, aggiungi le seguenti righe all'entry point 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 sull'analisi dello stack vengano raccolte correttamente.

Sono disponibili quattro opzioni per ComposeStackTraceMode:

  • Auto: opzione consigliata, in quanto utilizza GroupKeys se l'app è minimizzata e None in caso contrario.
  • GroupKeys: le analisi dello stack vengono create per le app minimizzate. Le informazioni sulla chiave di gruppo vengono conservate anche dopo la minimizzazione e vengono utilizzate insieme al file di mappatura di 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 operazioni aggiuntive in fase di runtime. Il compilatore Compose supporta l'emissione di mappature R8 aggiuntive a partire da Kotlin 2.3.0.
  • SourceInformation: utile per le build non minimizzate, 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'associazione di Layout Inspector. Vengono creati per essere utilizzati nelle versioni di debug delle app per ottenere letture accurate di un arresto anomalo che richiede maggiori informazioni sulla sua posizione. Le informazioni sull'origine vengono rimosse dalle app minimizzate per ottimizzare le dimensioni e le prestazioni dei file binari.
  • None: non sono stati aggiunti ulteriori dettagli sull'analisi dello stack.

Quando utilizzi l'opzione SourceInformation, l'analisi dello stack viene visualizzata come DiagnosticComposeException nell'elenco delle eccezioni soppresse:

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 relativi ai frame di analisi dello stack:

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 di origine avviene dopo un arresto anomalo, i dati della tabella degli slot possono essere incompleti e il numero di riga può essere eliminato. ReusableComposeNode e remember non producono informazioni sull'origine, quindi vedrai <unknown line> negli stack frame per queste funzioni.

Analisi dello stack delle chiavi di gruppo

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

Arresti anomali della raccolta di analisi dello stack

Se la raccolta dell'analisi dello stack si arresta in modo anomalo per qualsiasi motivo, l'eccezione viene aggiunta come eccezione soppressa anziché come DiagnosticComposeException.

Segnala eventuali arresti anomali soppressi o incoerenze nell'analisi dello stack al componente Compose Runtime.