Compose의 생명주기
컴포저블 수명 주기 | Jetpack Compose | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 컴포저블 수명 주기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 페이지에서는 컴포저블의 수명
developer.android.com
Jetpack Compose는 위 공식 문서에서 설명된 것처럼 특정한 생명주기를 따르고 있습니다.
생명주기는 위 그림과 같이 세 단계로 구성됩니다.
- Enter the Composition : 컴포저블이 처음 실행되어 UI를 구성합니다.
- Recomposition : State<T> 객체의 변경으로 인해 필요한 부분만 재 구성됩니다.
- Leave the Composition : 더 이상 필요하지 않으면 컴포지션이 종료됩니다.
컴포지션은 초기 컴포지션을 통해서만 생성되고 리컴포지션을 통해서만 업데이트 될 수 있습니다.
컴포지션을 수정하는 유일한 방법은 리컴포지션을 통하는 것이라고 설명하고 있습니다.
여기서 조금 더 깊게 들어가서, 어떻게 컴포저블이 화면에 그려지고 또 어떤 리컴포지션의 내부 동작으로 컴포저블이 수정되어 다시 그려지는 것인지 궁금해졌습니다.
Compose가 UI에 그려지는 과정
Jetpack Compose 단계 | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. Jetpack Compose 단계 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 대부분의 다른 UI 도구 키트와 마찬가
developer.android.com
- Composition : 컴포저블 함수가 실행되어 UI 트리를 구성합니다. 이 단계에서는 컴포저블이 화면에 무엇을 그릴지 정의합니다.
- Layout : UI 트리의 각 레이아웃 노드를 측정하고 화면에 배치합니다.
- Drawing : 최종적으로 각 노드가 차례로 하면에 그려집니다.
즉, 컴포저블 함수가 실행되면 화면에 UI를 그리기 위한 세 단계가 순차적으로 진행되어 화면에 그려집니다.
하지만 상태가 변경되어 리컴포지션이 일어날 때는, 전체를 다시 그리는 것이 아니라, 변경된 부분과 그 하위 트리만 재구성합니다.
이때, 재구성된 UI트리를 바탕으로 다시 Layout, Drawing 과정을 거처 화면에 그려지게 됩니다.
❓UI 트리는 누가 생성하고 어떻게 관리하는 걸까?
컴포지션 단계를 조금 더 자세하게 알아보겠습니다.
컴포지션 단계에서 컴포즈 런타임은 구성 가능한 함수를 실행하고 UI를 나타내는 트리 구조를 출력합니다. 이 UI 트리는 다음 단계에 필요한 모든 정보가 포함된 레이아웃 노드로 구성됩니다.
코드의 각 구성 가능한 함수는 UI 트리의 단일 레이아웃 노드에 매핑됩니다.
Row, Image, Column, Text 등의 컴포저블이 각각의 단일 노드에 매핑되는 것은 내부 코드를 통해 확인할 수 있었습니다.
간단하게 Column과 Text의 내부 코드를 확인해봤습니다.
Column 내부 코드에서 Layout을 호출하고 있었으며, Text 내부에서 호출한 BasicText 역시 Layout을 호출하고 있었습니다.
Layout 컴포저블 내부에서는 ReusableComposeNode 함수를 실행하고 있었습니다.
이 ReusableComposeNode는 이름 그대로 재사용 가능한 노드가 생성되는 메서드이고, 내부 코드를 통해 어떤 작업을 수행하고 있는 지 알 수 있었습니다.
currentComposer라는 프로퍼티에 의해 노드가 생성되어 트리에 삽입되고, 업데이트되고 종료되는 것을 확인할 수 있었습니다.
❓그렇다면 currentComposer가 무엇일까??
currentComposer는 Composer 타입의 프로퍼티입니다.
주석으로 처리된 것을 번역하면 아래와 같습니다.
Composer는 Kotlin Compose 컴파일러 플러그인의 타깃이 되고 코드 생성 도우미가 사용하는 인터페이스입니다.
런타임에서는 호출이 컴파일러에 의해 생성되고 최소한의 상태 검증만 포함된다고 가정하므로 직접 호출은 피하는 것이 좋습니다.
즉, Kotlin Compose 컴파일러에 의해 생성된 Composer가 컴포지션 단계에서 UI 트리를 생성하고 관리하는 것이었습니다.
Composer가 UI 트리를 관리하는 방법은 Composer의 구현체인 ComposerImpl 코드에서 확인할 수 있었습니다.
SlotTable에 의해 컴포지션 데이터가 사용되고 저장되는 것입니다.
Under the hood of Jetpack Compose — part 2 of 2
Under the hood of Compose
medium.com
자세한 것은 위 개발자 블로그에서 찾아볼 수 있었습니다.
SlotTable은 Gap Buffer를 이용하여 컴포지션 데이터를 저장, 관리합니다.
비어 있는 공간은 Gap이고, 데이터가 들어오게 된다면 순차적으로 쌓이고 커서를 다음 위치로 이동시킵니다.
만약 데이터의 변경으로 인해 리컴포지션이 일어나게 된다면, 커서를 배열의 맨 위로 재설정한 후, 처음부터 데이터를 다시 확인하고 값을 업데이트하거나 Skip하게 됩니다.
만약 데이터가 중간에 삽입된다면 아래의 그림처럼 동작합니다.
커서를 삽입하고자 하는 위치까지 이동시킨 후 Gap을 해당 위치까지 옮깁니다.
그 후 원하는 값들을 다시 순차적으로 삽입하는 것입니다.
이러한 Gap Buffer라는 데이터 구조는 Gap을 이동시키는 데 O(N)의 시간복잡도를 가지고, Gap을 이동시키는 것 이외의 모든 작업은 O(1)의 시간복잡도를 가지는 특징으로 인해 사용됩니다.
이 데이터 구조를 선택한 이유는 평균적으로 UI가 구조를 크게 변경하지 않는다는 특성 때문이라고 합니다. Compose 팀은 UI 구조 자체가 많이 변경되지 않을 것이고, 데이터의 변경으로 UI가 변경되는 경우가 많을 것이라고 가정했습니다. 그리고 데이터 변경으로 UI가 변경되는 연산은 빠른시간에 연산될 수있는 전략을 취하기 위해 Gap buffer를 선택했다고 설명되어 있습니다.
내부 코드를 열심히 까보며 학습하고 있지만 너무 어렵습니다...😭
컴포즈를 사용하기 앞서 어떤 방식으로 동작하는지 짚고 넘어가려고 했으나... 생각보다 많이 어렵네요...
이후에는 Layout, Drawing 과정을 간단하게 내부 코드와 함께 확인하고, 리컴포지션이 일어나는 조건과 과정에 대해 알아보려고 합니다.

It's So Hard..!
'안찌의 개발일기 > Android' 카테고리의 다른 글
[Kotlin] Coroutine의 모든 것 (0) | 2025.02.12 |
---|---|
[Android] by remember의 리컴포지션 문제 (Compose) (1) | 2024.11.19 |
[Android] Compose Preview 심폐소생술!! (0) | 2024.11.19 |
[Android] 서버 통신 (2) | 2024.09.25 |
[Android] 코루틴 (Coroutine) (1) | 2024.06.18 |