Compose의 스택 트레이스

Jetpack Compose는 여러 다른 단계에서 코드를 실행하므로 @Composable 함수의 일부가 서로 별도로 실행됩니다. 이러한 단계에서 비정상 종료가 발생하면 해석하기 어려운 스택 트레이스가 발생하여 비정상 종료를 일으킨 정확한 함수나 코드 줄을 파악하기 어려울 수 있습니다.

소스 정보를 스택 트레이스에 추가

스택 트레이스 가독성을 개선하기 위해 선택 API는 컴포저블 이름과 위치를 비롯한 더 풍부한 비정상 종료 위치 세부정보를 제공하므로 다음 작업을 할 수 있습니다.

  • 비정상 종료 소스를 효율적으로 식별하고 해결
  • 재현 가능한 샘플의 비정상 종료 격리
  • 이전에는 내부 스택 프레임만 표시되었던 비정상 종료 조사

Compose 런타임은 컴포지션에서 비정상 종료 위치를 감지하고 @Composable 계층 구조를 기반으로 스택 트레이스를 재구성할 수 있습니다. 다음의 비정상 종료에 스택 트레이스가 추가됩니다.

  • 구성
  • DisposableEffectLaunchedEffect (onDispose 또는 취소 제외)
  • rememberCoroutineScope에서 실행된 코루틴
  • 패스 측정, 레이아웃, 그리기

이 기능을 사용 설정하려면 애플리케이션 진입점에 다음 줄을 추가하세요.

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

스택 트레이스 정보가 올바르게 수집되는지 확인하려면 컴포지션을 만들기 전에 이 구성을 실행하는 것이 좋습니다.

ComposeStackTraceMode에는 다음 네 가지 옵션이 있습니다.

  • Auto: 앱이 축소되면 GroupKeys를 사용하고 그렇지 않으면 None를 사용하므로 권장되는 옵션입니다.
  • GroupKeys: 축소된 앱에 스택 트레이스가 생성됩니다. 그룹 키 정보는 축소 후에도 유지되며 Compose 컴파일러와 R8에서 내보낸 ProGuard 매핑 파일과 함께 @Composable 함수의 대략적인 위치를 재구성하는 데 사용됩니다. 이러한 스택 트레이스는 정확도가 떨어지며 런타임에 추가 작업을 하지 않도록 최적화되어 있습니다. Compose 컴파일러는 Kotlin 2.3.0부터 추가 R8 매핑의 방출을 지원합니다.
  • SourceInformation: 축소되지 않은 빌드에 유용하며 소스 정보를 수집하여 스택 트레이스에 추가합니다. 결과는 더 정확하지만 레이아웃 인스펙터를 연결하는 것과 비슷한 상당한 성능 비용이 발생합니다. 위치에 관한 추가 정보가 필요한 비정상 종료에 관한 정확한 판독값을 얻기 위해 앱의 디버그 버전에서 사용하도록 생성됩니다. 소스 정보는 바이너리 크기와 성능을 최적화하기 위해 축소된 앱에서 삭제됩니다.
  • None: 추가 스택 트레이스 세부정보가 추가되지 않았습니다.

SourceInformation 옵션을 사용하면 스택 트레이스가 억제된 예외 목록에 DiagnosticComposeException로 표시됩니다.

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)

알려진 제한사항

스택 트레이스 프레임에는 몇 가지 알려진 문제가 있습니다.

소스 정보 스택 트레이스

구성에서 비정상 종료의 첫 번째 스택 프레임에 줄 번호 (<unknown line>)가 누락됨 소스 정보 인트로스펙션은 비정상 종료 후에 발생하므로 슬롯 테이블 데이터가 불완전하고 줄 번호가 누락될 수 있습니다. ReusableComposeNoderemember는 소스 정보를 생성하지 않으므로 이러한 함수의 스택 프레임에 <unknown line>가 표시됩니다.

그룹 키 스택 트레이스

GroupKeys 기반 스택 트레이스는 설계상 @Composable 함수의 첫 번째 줄만 가리킬 수 있습니다. 그룹을 생성하지 않는 함수 (예: 인라인 또는 Unit을 반환하지 않는 함수)의 데이터도 포함하지 않습니다.

스택 트레이스 수집 비정상 종료

스택 트레이스 수집이 어떤 이유로든 비정상 종료되면 해당 예외가 DiagnosticComposeException 대신 억제된 예외로 추가됩니다.

억제된 비정상 종료 또는 스택 트레이스 불일치를 Compose 런타임 구성요소에 신고합니다.