지난 글: [Android] Compose의 모든 것(3) - State, MutableState, remember, rememberSaveable, by, = 선언 방식 차이
https://yujinius45.tistory.com/141
[Android] Compose의 모든 것(3) - State, MutableState, remember, rememberSaveable, by, = 선언 방식 차이
지난 글: [Android] Compose의 모든 것(2) - Lifecycle, UI 렌더링, Recomposition과 Statehttps://yujinius45.tistory.com/140 [Android] Compose의 모든 것(2) - Lifecycle, UI 렌더링, Recomposition과 State지난 글: [Android] Compose의 모든
yujinius45.tistory.com
Jetpack Compose는 상태(State)를 기반으로 UI를 효율적으로 구성하고, 변경된 부분만 다시 그리는 Recomposition이라는 최적화된 메커니즘을 제공한다. 이번 글에서는 Recomposition이 어떤 원리로 동작하는지, 내부 코드를 분석하여 작동 방식을 파헤치고, UI 트리 구성도 함께 보고자 한다.
오늘의 주요 포인트 ⭐
- Recomposition의 정의와 동작 과정: State 읽기, 변경 감지, 재구성 실행.
- Snapshot 시스템: State 읽기 시점을 추적하고 상태 변경을 감지.
- UI 트리 구성 원리: ComposeNode의 역할과 UI 트리 생성 과정.
Recomposition이란?
Recomposition은 상태(State) 변경을 감지하고, 해당 상태와 연결된 Composable 함수를 다시 실행하는 과정이다. Compose는 이 과정을 통해 필요한 UI 부분만 효율적으로 업데이트한다.
Recomposition의 동작 과정
- State 읽기: Compose는 상태를 읽는 시점을 추적한다.
- State 변경 감지: 상태 값이 변경되면, 해당 상태를 읽고 있는 Composable 함수가 재구성 대상이 된다.
- 재구성 실행: 이전 UI 트리와 변경된 상태를 비교하여, 변경된 부분만 다시 실행한다.
“상태(State) 변경을 감지, State 읽는 시점을 추적” 한다는 것이 무슨 소리일까? 내부적으로 어떻게 가능한지 궁금했다.
State 읽는 시점을 어떻게 추적할까?
Snapshot 시스템

- SnapshotState.kt 캡쳐
Compose에서 State는 Snapshot 시스템으로 관리된다. Snapshot 시스템은 상태를 추적하고 변경 사항을 감지하는 메커니즘으로, State가 읽히는 시점(State Read)을 기록한다. 이로 인해 State 값이 변경되면 해당 상태를 구독 중인 Composable 함수가 감지하고 Recomposition을 트리거한다.
Snapshot 시스템은 Compose의 내부 상태 관리를 담당하며, 다음과 같은 역할을 한다:
- State 변경 감지: State를 읽는 순간 해당 Composition 범위가 상태 변경을 구독(subscribe)하며, State 값이 변경될 경우 이를 자동으로 감지한다.
- Recomposition 연결: 변경된 State와 관련된 Composable 함수만 다시 실행되어 효율적으로 UI를 업데이트한다.
이를 통해 Jetpack Compose는 UI 변경 사항을 최소화하면서 필요한 부분만 효율적으로 다시 그릴 수 있다. 이에 대해 아래와 같이 다이어그램으로 흐름을 정리해보았다.

일단 Recomposition이 발생하기 직전 State를 어떻게 감지하고 있는지 스냅샷 시스템을 통해 이루어지고 있다는 것을 확인했다. 그렇다면 이제 Recomposition이 어떻게 발생하는지 확인해야 하는데, 그 전에 본격적으로 Recompositon 동작 원리를 살피기 전 Composable이 UI트리로 구성되는 원리부터 코드를 보며 살펴보자.
Composable이 UI 트리로 구성되는 원리
Compose에서 모든 UI는 Composable 함수 호출로 시작하여, 내부적으로 UI 트리를 구성하는 과정으로 이어진다. 이에 대한 내용은 이전 포스팅에서 확인할 수 있다. 그런데 과연 내부적으로 어떤 정보를 포함하고 동작될까? 이를 알아보자.
Compose UI 트리는 노드(Node)를 기반으로 이루어지며, 각각의 노드는 상태(State), 레이아웃, 그리기 정보 등을 포함한다. Composable 함수는 호출 시 ComposeNode를 통해 노드를 생성하거나 업데이트하며 트리에 추가한다. 아래의 코드를 참고하면 된다.

- Composables.kt의 ComposeNode코드 참고
ComposeNode의 역할
ComposeNode는 Composable 함수가 호출될 때 실행되며, 결과적으로 UI 트리를 구성하는 핵심 역할을 수행한다. 주요 동작은 다음과 같다:
- 노드 생성 및 초기화:
- 새로운 노드를 생성하거나 기존 노드를 재사용하여 트리를 효율적으로 관리한다.
- currentComposer.startNode() 및 createNode()를 통해 노드를 생성한다.
- 노드 속성 업데이트:
- Updater와 SkippableUpdater를 사용해 노드의 속성을 갱신한다.
- SkippableUpdater는 상태 변경이 없는 경우 실행을 건너뛸 수 있어 최적화에 기여한다.
- 자식 노드 처리:
- content를 호출하여 자식 Composable을 실행하고 하위 노드를 트리에 추가한다.
- 자식 노드는 그룹화되어 관리된다.
- 노드 종료:
- currentComposer.endNode()를 호출하여 노드 추가 작업을 종료한다.
UI 트리 구성 과정
ComposeNode의 동작 흐름을 간단히 살펴보면 다음과 같다:
@Composable
fun CustomBox(content: @Composable () -> Unit) {
ComposeNode<CustomNode, CustomApplier>(
factory = { CustomNode() }, // 노드 생성
update = {
set(/* 업데이트 로직 */) // 속성 갱신
},
skippableUpdate = {
// 상태 변경이 없으면 스킵 가능
},
content = content // 자식 Composable 호출
)
}
위 코드에서 ComposeNode는 CustomNode라는 노드를 생성하거나 업데이트하고, 자식 Composable 호출로 트리를 확장한다.
위의 Composables.kt의 ComposeNode코드를 통해 Composable 함수 호출 시 UI가 노드로 구성된 트리 구조로 생성되고 관리됨을 알 수 있다. 이 과정은 Recomposition의 동작 원리를 이해하는 데 중요한 배경 지식을 제공한다.
그렇다면 이러한 ComposeNode로 UI 트리가 구성된다는 것은 알았는데 State, key 같은 것은 어디에 저장되어 관리될까?
이는 분량 상 너무 길어지는 것 같으므로 다음 글로 넘기겠다.
[Android] Compose의 모든 것(5) - Slot Table, Stability, Key를 활용한 Recomposition 최적화
https://yujinius45.tistory.com/143
[Android] Compose의 모든 것(5) - Slot Table, Stability, Key를 활용한 Recomposition 최적화
지난 글: [Android] Compose의 모든 것(4) - Recomposition의 동작 원리와 Compose UI 트리 구성 파헤치기https://yujinius45.tistory.com/142 [Android] Compose의 모든 것(4) - Recomposition의 동작 원리와 Compose UI 트리 구성 파
yujinius45.tistory.com