초기 Composition 과정
새 Composition이 생성되면 setContent()를 통해 초기 Composition이 시작된다. setContent()는 전달받은 Composable content를 현재 Composition에 저장한 뒤, parent.composeInitial()을 호출하여 초기 구성을 상위 CompositionContext에 위임한다.
루트 Composition의 parent는 Recomposer이고, Subcomposition의 parent는 상위 Composition이다. 하지만 Subcomposition도 위임 체인을 따라가면 결국 Recomposer에 도달하므로, 초기 Composition의 실제 실행 제어는 최종적으로 Recomposer가 담당한다고 볼 수 있다.
따라서 parent.composeInitial 호출은 recomposer.composeInitial로 변환될 수 있으며, 여기서 초기 composition을 구축하기 위해 몇 가지 중요한 작업을 수행한다.
- Recomposer.composeInitial()은 초기 Composition을 바로 실행하지 않고, MutableSnapshot 안에서 실행한다.
- 이때 read/write observer를 등록해 Composition 중 읽거나 변경된 State를 추적하고, snapshot.enter { composition.composeContent(content) } 블록 안에서 실제 Composition을 수행한다.
- 실제 Composable 실행과 SlotTable 기록은 Composer가 담당하며, Composition이 완료되면 snapshot.apply()를 통해 스냅샷 내부 변경 사항을 전역 Snapshot 상태에 반영한다.
- 실제 코드 Recomposer.composeInitial()
Composer에게 위임된 실제 composition 과정들은 다음과 같다.
- Composition 중에는 재진입이 허용되지 않으며, Composer는 이를 방지하는 내부 상태 검사를 수행한다.
- 보류중인 invalidation을 내부 구조로 옮기고, 해당 RecomposeScope들을 이후 recomposition 대상으로 관리한다.
- Composition 시작 시 isComposing을 true로 설정한다.
- startRoot()를 호출하여 루트 그룹을 시작하고, SlotTable 기록을 위한 초기 상태를 설정한다.
- startGroup()을 통해 content 그룹을 열며, 이는 recomposition을 위한 scope 단위로 기록된다.
- content 람다를 실행하면서 Composable 호출 구조를 SlotTable에 기록하고 변경 사항을 축적한다.
- endGroup()으로 그룹을 닫고, endRoot()로 전체 composition을 마무리한다.
- Composition 종료 후 isComposing을 false로 되돌린다.