Registros de seguimiento de pila en Compose

Jetpack Compose ejecuta tu código en varias fases diferentes, lo que hace que algunas partes de la función @Composable se ejecuten por separado. Las fallas en estas fases pueden generar seguimientos de pila difíciles de descifrar, lo que dificulta identificar la función o la línea de código exactas que provocaron la falla.

Agrega información de la fuente a los seguimientos de pila

Para mejorar la legibilidad del seguimiento de pila, una API opcional proporciona detalles más enriquecidos sobre la ubicación de la falla, incluidos los nombres y las ubicaciones de los elementos componibles, lo que te permite hacer lo siguiente:

  • Identifica y resuelve de manera eficiente las fuentes de fallas
  • Aísla las fallas para obtener muestras reproducibles
  • Investiga las fallas que antes solo mostraban marcos de pila internos.

El tiempo de ejecución de Compose puede detectar la ubicación de la falla en la composición y reconstruir un seguimiento de pila según tu jerarquía de @Composable. El seguimiento de pila se agrega a las fallas en los siguientes casos:

  • Composición
  • DisposableEffect y LaunchedEffect (excepto onDispose o cancelación)
  • Corrutiinas iniciadas en rememberCoroutineScope
  • Medición, diseño y trazado de pases

Para habilitar esta función, agrega las siguientes líneas al punto de entrada de la aplicación:

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

Lo ideal es realizar esta configuración antes de crear cualquier composición para verificar que la información del registro de seguimiento se recopile correctamente.

Existen cuatro opciones para ComposeStackTraceMode:

  • Auto: Opción recomendada, ya que usa GroupKeys si la app está minimizada y None en otros casos.
  • GroupKeys: Se crean seguimientos de pila para las apps reducidas. La información de la clave de grupo se conserva incluso después de la minificación y se usa junto con el archivo de asignación de ProGuard que emiten el compilador de Compose y R8 para reconstruir una ubicación aproximada de las funciones @Composable. Estos seguimientos de pila son menos precisos y están optimizados para evitar trabajo adicional en el tiempo de ejecución. El compilador de Compose admite la emisión de asignaciones adicionales de R8 a partir de Kotlin 2.3.0.
  • SourceInformation: Es útil para las compilaciones no minimizadas, recopila información de la fuente y la agrega al seguimiento de pila. Los resultados son más precisos, pero generan un costo de rendimiento significativo similar al de adjuntar el inspector de diseño. Se crean para usarse en versiones de depuración de las apps y obtener lecturas precisas sobre una falla que requiere más información sobre su ubicación. La información de la fuente se quita de las apps reducidas para optimizar el tamaño y el rendimiento del archivo binario.
  • None: No se agregaron detalles adicionales del registro de seguimiento de la pila.

Cuando se usa la opción SourceInformation, el seguimiento de pila aparece como un DiagnosticComposeException en la lista de excepciones suprimidas:

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)

Limitaciones conocidas

Existen algunos problemas conocidos con los marcos de seguimiento de pila:

Seguimientos de pila de información de fuente

Faltan números de línea (<unknown line>) en el primer marco de pila para las fallas en la composición. Dado que la introspección de la información de la fuente se produce después de una falla, los datos de la tabla de ranuras pueden estar incompletos y omitir el número de línea. ReusableComposeNode y remember no producen información de la fuente, por lo que verás <unknown line> en los marcos de pila de esas funciones.

Seguimientos de pila de claves de grupo

Por diseño, los seguimientos de pila basados en GroupKeys solo pueden apuntar a la primera línea de la función @Composable. Tampoco contienen datos para las funciones que no producen un grupo (como las funciones intercaladas o las que no devuelven una unidad).

Fallas en la recopilación de seguimientos de pila

Si la recopilación del seguimiento de pila falla por algún motivo, esa excepción se agrega como una excepción suprimida en lugar de DiagnosticComposeException.

Informa cualquier bloqueo suprimido o inconsistencia en el registro de pila al componente de Compose Runtime.