-
Compose UI 디버깅 핵심 정리 — Layout Inspector부터 Recomposition 추적까지카테고리 없음 2026. 4. 1. 14:07

Compose UI 디버깅이 필요한 이유
Jetpack Compose는 선언형 UI 패러다임을 채택하면서 기존 View 시스템과는 완전히 다른 디버깅 방식을 요구한다.
XML 기반의 View 계층 구조를 직접 탐색하던 방식과 달리, Compose는 함수 호출 체인과 상태(State) 흐름을 이해해야 문제를 파악할 수 있다.
특히 Recomposition이 예상보다 잦거나, UI가 상태 변화에 반응하지 않는 경우 원인을 찾기 어렵기 때문에 체계적인 디버깅 도구와 전략이 필수적이다.Layout Inspector로 Compose 계층 구조 분석하기
Android Studio에 내장된 Layout Inspector는 Compose UI를 실시간으로 시각화하는 가장 강력한 도구 중 하나다.
Run > Profiler 또는 View > Tool Windows > Layout Inspector를 통해 실행할 수 있으며, 앱이 실행 중인 상태에서 연결하면 현재 화면의 Composable 트리를 3D 레이어 뷰로 확인할 수 있다.특히 주목해야 할 기능은 Recomposition Count 표시다.
각 Composable 옆에 표시되는 숫자가 해당 함수가 몇 번 재구성되었는지 알려준다.
이 숫자가 지나치게 높으면 불필요한 Recomposition이 발생하고 있다는 신호이므로, 상태 범위를 좁히거나remember를 활용해 최적화해야 한다.// 잘못된 예: 상위 상태가 변할 때마다 전체 재구성 발생 @Composable fun ParentComposable() { var count by remember { mutableStateOf(0) } Text("Count: $count") HeavyComposable() // count 변화와 무관하지만 재구성됨 } // 개선: 상태를 필요한 Composable에만 전달 @Composable fun ParentComposable() { var count by remember { mutableStateOf(0) } CountText(count = count) HeavyComposable() // 이제 재구성되지 않음 }Recomposition 디버깅 — SideEffect와 로그 활용
Recomposition 문제를 추적할 때 가장 간단한 방법은
SideEffect를 활용한 로깅이다.SideEffect는 Recomposition이 발생할 때마다 실행되므로, 특정 Composable이 얼마나 자주 재구성되는지 확인하는 데 유용하다.@Composable fun MyComposable(data: SomeData) { SideEffect { Log.d("Compose", "MyComposable recomposed with: $data") } // 나머지 UI 코드 }또한
remember와key를 올바르게 사용하는 것이 중요하다.LazyList내의 아이템에서 고유한key를 지정하지 않으면, 목록 변경 시 모든 아이템이 재구성될 수 있다.items(list, key = { it.id })형태로 key를 명시하면 Compose가 변경된 아이템만 효율적으로 재구성한다.LazyColumn { items( items = myList, key = { item -> item.id } // 반드시 고유한 키 지정 ) { item -> ItemComposable(item = item) } }Preview 디버깅 — @Preview 매개변수 적극 활용
@Preview어노테이션은 단순히 UI를 미리 보는 용도를 넘어, 다양한 조건을 시뮬레이션하는 강력한 디버깅 도구다.showBackground,showSystemUi,uiMode,fontScale,locale등의 매개변수를 조합해 실제 기기 없이도 다양한 시나리오를 테스트할 수 있다.@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(name = "Large Font", fontScale = 1.5f) @Preview(name = "RTL", locale = "ar") @Composable fun MyComposablePreview() { MyTheme { MyComposable(data = sampleData) } }여러
@Preview를 동시에 정의하면 각 조건에서의 렌더링 결과를 나란히 확인할 수 있어 엣지 케이스를 사전에 발견하는 데 효과적이다.
특히 텍스트 오버플로, 다크 모드 색상 대비, 긴 문자열 처리 등 자주 놓치는 UI 문제를 Preview 단계에서 잡을 수 있다.상태(State) 디버깅 — StateFlow와 ViewModel 연동 확인
Compose UI의 상태 문제 대부분은 ViewModel과 StateFlow 연동에서 발생한다.
collectAsState()또는collectAsStateWithLifecycle()을 통해 상태를 수집할 때, 적절한 Lifecycle 범위를 지정하지 않으면 백그라운드에서도 Flow가 수집되어 불필요한 리소스 낭비가 발생한다.// 권장: Lifecycle을 고려한 상태 수집 val uiState by viewModel.uiState.collectAsStateWithLifecycle() // 주의: collectAsState()는 Lifecycle 인식 없이 항상 수집 val uiState by viewModel.uiState.collectAsState()또한
StateFlow의 초기값과 실제 UI 반영 사이의 타이밍 문제를 의심해야 할 때는 Android Studio의 App Inspection > Database Inspector나 Network Inspector를 함께 활용해 데이터 흐름 전체를 추적하는 것이 효과적이다.
디버그 빌드에서 ViewModel의 상태를 직접 출력하는 방법도 간단하고 유용하다.// ViewModel에서 상태 변화 추적 class MyViewModel : ViewModel() { private val _uiState = MutableStateFlow(UiState.Loading) val uiState: StateFlow<UiState> = _uiState.asStateFlow() init { viewModelScope.launch { _uiState.collect { state -> Log.d("ViewModel", "State changed: $state") } } } }Compose 성능 디버깅 — Tracing과 Baseline Profile
UI 버벅임이나 렌더링 지연이 발생할 때는 Android Studio의 Profiler를 통해 Compose의 측정(Measure), 레이아웃(Layout), 그리기(Draw) 단계를 분석해야 한다.
특히TraceEvent를 코드에 직접 삽입하면 특정 Composable의 실행 시간을 Profiler에서 정밀하게 확인할 수 있다.// 성능 측정을 위한 Trace 삽입 @Composable fun HeavyComposable() { androidx.compose.runtime.trace("HeavyComposable") { // 측정하고 싶은 UI 코드 ComplexLayout() } }Baseline Profile을 생성하면 앱 초기 실행 시 Compose 코드를 미리 컴파일하여 첫 프레임 렌더링 속도를 크게 개선할 수 있다.
BaselineProfileRule을 사용한 프로파일 생성은 실제 사용자 경험을 측정하는 가장 현실적인 방법이다.
반복적으로 느린 화면이 있다면 해당 화면의 진입 경로를 Baseline Profile에 포함시키는 것을 권장한다.마무리 — Compose 디버깅의 핵심 원칙
Compose UI 디버깅의 핵심은 상태 흐름을 단방향으로 유지하고, Recomposition 범위를 최소화하는 데 있다.
Layout Inspector의 Recomposition Count, SideEffect 로깅, Preview 다양화, collectAsStateWithLifecycle 사용, Profiler 트레이싱을 조합하면 대부분의 Compose 관련 문제를 체계적으로 해결할 수 있다.
처음에는 낯설게 느껴지지만, 도구에 익숙해질수록 View 시스템보다 훨씬 명확하게 문제의 원인을 파악할 수 있다는 것이 Compose 디버깅의 장점이다.