Compose Runtime이 상태(State) 의 변경을 감지하고
UI 재구성을 효율적으로 수행하기 위해 사용하는 데이터 일관성(Consistency) 관리 시스템입니다.
간단히 말해,
Compose는 멀티스레드에서 상태를 바꿀 수도 있고,
Recomposition은 비동기적으로 발생합니다.
그래서 다음 두 가지 문제가 생길 수 있죠:
| 문제 | 설명 |
|---|---|
| 데이터 불일치 | 한 스레드가 상태를 읽는 도중 다른 스레드가 값을 바꾸면 UI가 꼬임 |
| 불필요한 Recomposition | 바뀌지 않은 상태까지 다시 그림 |
💡 Snapshot 시스템의 역할:
상태를 읽고 쓰는 시점을 “스냅샷(사진)”처럼 캡처해서
변경과 참조를 정교하게 추적하고, 필요한 UI만 다시 그리게 한다.
| 구성 요소 | 설명 |
|---|---|
| Snapshot | 상태 값의 일관된 시점(View)을 나타내는 객체 |
| SnapshotMutableState | Compose의 mutableStateOf()가 내부적으로 사용하는 상태 래퍼 |
| SnapshotRecord | 상태 변경을 추적하기 위한 레코드(버전 정보 포함) |
| SnapshotObserver | 어떤 상태를 읽었는지 관찰하고, 변경 시 재구성을 트리거 |
| ApplyScope | 상태 변경을 실제로 커밋하는 영역 (atomic commit) |
[mutableStateOf(0)]
│
▼
SnapshotMutableState
│
┌───┴───────────────────────────────────┐
│ SnapshotRecord(version, value) │
│ SnapshotObserver: who read this? │
└───────────────────────────────────────┘
│
▼
Compose Runtime registers observer
(so it knows which composable depends on this state)
state.value를 읽을 때, Snapshot Observer가 “이 컴포저블이 이 상태를 읽었다”고 기록합니다.val count by remember { mutableStateOf(0) }
Text("Count: $count")
➡ 내부 동작:
SnapshotObserver:
Text() 컴포저블이 count 상태를 참조함
count++ 처럼 상태가 바뀌면 Snapshot 시스템이 “해당 상태를 읽은 모든 구독자(컴포저블)”를 탐색합니다.➡ 즉, Snapshot이 변경을 감지하고
“누가 이 데이터를 보고 있었는지”를 알고 있기 때문에
필요한 부분만 정확히 다시 그려줍니다.
Compose는 상태 변경을 트랜잭션처럼 처리합니다.
┌───────────────────────────┐
│ 1️⃣ Snapshot Open │ ← 상태 변경 시작
│ 2️⃣ Modify Record │ ← 새 값 기록 (임시)
│ 3️⃣ Apply (Commit) │ ← 모든 변경을 일괄 반영
│ 4️⃣ Notify Observers │ ← 관련 컴포저블 재구성 요청
└───────────────────────────┘
이 덕분에 여러 상태가 동시에 바뀌어도
UI는 일관된 한 시점의 값만 본다.
rememberCoroutineScope() 등에서 비동기로 상태를 바꾸는 경우도,
Snapshot은 코루틴 내부의 상태 변경까지 감지합니다.
val scope = rememberCoroutineScope()
val state = remember { mutableStateOf(0) }
Button(onClick = { scope.launch { state.value++ } }) {
Text("Click ${state.value}")
}
state.value++ 수행💡 즉, CoroutineScope는 실행의 단위,
Snapshot은 상태 일관성 관리의 단위,
그리고 Runtime이 그 둘을 통합적으로 제어합니다.
CoroutineScope.launch { state.value++ } // suspend context에서 상태 변경
│
▼
Snapshot Write detected by Runtime
│
▼
Snapshot Commit → Notify Observers
│
▼
Runtime marks affected Composables as invalid
│
▼
Recomposition Scheduler executes → affected UI redraw
| 항목 | 설명 |
|---|---|
| 일관성(Consistency) | 여러 상태를 동시에 변경해도 UI는 한 시점만 본다 |
| 정확한 변경 감지 | 어떤 UI가 어떤 상태를 읽었는지 추적 |
| 부분적 재구성 | 전체 UI 대신 필요한 컴포저블만 다시 그림 |
| 스레드 안전성 | 스냅샷 단위로 변경을 관리하여 병행 접근 안정화 |
| 비동기 안정성 | Coroutine 등 비동기 변경도 안전히 반영 |
Snapshot은 런타임의 타임머신입니다.
런타임이 매 순간 상태의 “사진(Snapshot)”을 찍어두고,
새로운 변경이 생기면
“이 사진을 참조하던 컴포넌트만 다시 갱신”하는 구조입니다.
Snapshot은 Compose Runtime 내부의 상태 관리 핵심 엔진으로,
모든
mutableStateOf값을 트랜잭션처럼 추적·커밋하며필요한 컴포저블만 재구성되도록 보장한다.
즉, Compose의 반응형·일관된 UI를 가능하게 하는 런타임 레벨의 뇌(Brain) 이다.