Jetpack Compose Recomposition Physics
Jetpack Compose Recomposition 메커니즘의 정의, 범위, 선행 지식, 학습 주제, 참고 근거를 정리한 CS&E 학습 노드입니다.
목차 보기20
1. Overview
Jetpack Compose 리컴포지션 물리(Jetpack Compose Recomposition Physics)는 안드로이드의 구형 XML 레이아웃 구조를 타파하고, 상태(State)가 변할 때마다 화면을 기계적으로 새로 그리는 선언형 UI 프레임워크의 렌더링 역학을 다룹니다.
과거에는 findViewById로 버튼 객체를 찾아 setText로 텍스트를 강제로 덮어씌웠으나(명령형), Compose는 데이터 상태(State)를 컴포저블(Composable) 함수에 부어주면 알아서 화면이 튀어나오는 함수형 패러다임을 따릅니다. 하지만 데이터가 1초에 60번 바뀌면 함수도 60번 재실행(Recomposition)되어야 하므로 극심한 성능 병목이 발생할 수 있습니다. 학습자는 프레임워크가 트리 전체를 다시 그리지 않고 '변경이 발생한 국소 부위'만 찾아내 다시 실행하는 스마트 리컴포지션(Smart Recomposition) 알고리즘을 해부하고, 상태를 안정적(Stable)으로 설계하여 불필요한 재렌더링을 차단하는 렌더링 방어막을 구축합니다.
2. Scope & Boundaries
In-Scope
- Compose 아키텍처:
@Composable어노테이션의 컴파일러 변환, UI 렌더링 트리 구조. - 상태와 리컴포지션:
State,MutableState, 스마트 리컴포지션(Smart Recomposition), 상태 호이스팅(State Hoisting). - 성능 렌더링 방어:
remember,derivedStateOf, Immutable/Stable 객체 물리. - 부수 효과(Side Effects):
LaunchedEffect,DisposableEffect, 코루틴-UI 라이프사이클 바인딩.
Out-of-Scope
- iOS SwiftUI 렌더링 역학: 뷰 구조체(Struct) 기반의 차이 연산(Diffing) 메커니즘 13-01-02. UIKit vs SwiftUI Rendering Physics 영역으로 위임.
- 웹 React Virtual DOM: 브라우저의 DOM 트리 갱신 및 Reconciliation 알고리즘 14-02-01. Virtual DOM Reconciliation 영역으로 위임.
Boundaries
- XML vs Compose: XML은 뷰 객체(View) 인스턴스를 메모리에 들고 상태를 직접 조작하는 Stateful 구조라면, Compose는 상태가 들어오면 트리 조각을 완전히 새로 뱉어내고 이전 조각을 버리는 Stateless 함수형 렌더링 역학입니다.
3. Counterexample
- 명령형 상태 관리 (Imperative State Fallacy): Compose 안에서 외부의 일반 전역 변수(var)나 일반 리스트를 변경하며 화면이 왜 업데이트 안 되냐고 헤매는 행위. Compose는 컴파일러 레벨에서 관찰 가능한(Observable)
State객체의 변경 이벤트만 감지하여 렌더링을 켭니다. 반드시mutableStateOf로 감싸야 합니다. - 무한 리컴포지션 폭주 (Recomposition Loop Fallacy): 텍스트 입력창이나 스크롤 뷰 안에 복잡한 정렬(Sort) 연산을 그대로 넣어두는 무지. 스크롤할 때마다(초당 60회) 리컴포지션이 발생하면서 정렬 연산도 초당 60번 돌아가 앱이 멈춰버립니다. 변하지 않는 값이나 무거운 계산은 무조건
remember나derivedStateOf로 감싸서 이전 계산값을 캐싱(Memoization)해야 합니다.
4. Prerequisites
- 함수형 프로그래밍 (Basic): 함수가 부수 효과(Side Effect) 없이 동일한 입력에 동일한 출력(멱등성)을 낸다는 순수 함수의 개념을 알아야 합니다. (05-01. Programming Paradigms)
- 코틀린 언어 물리 (Recommended): 코루틴과 상태 플로우(StateFlow)의 비동기 흐름을 이해해야 Compose에 상태를 주입할 수 있습니다. (13-02-01. Kotlin & JVM-ART)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 선언형 UI와 @Composable 역학
- Why to Learn: 뷰(View)의 상태를 손으로 일일이 바꾸다 버그를 양산하는 명령형 방식에서 탈피하여, 렌더링을 프레임워크에 위임하기 위함입니다.
- What to Learn: Declarative UI,
@Composable컴파일러 플러그인, 계층(Tree) 조립. - How to Learn: 일반 Kotlin 함수에
@Composable어노테이션을 붙이는 순간, 내부적으로 노드(Node) 트리를 방출(Emit)하는 복잡한 매개변수(Composer)가 숨겨져 들어가는 컴파일러의 물리적 마법을 이해합니다. - Implement: 조건문(
if,for)을 섞어, 입력된 데이터 리스트의 개수에 따라 완전히 다른 UI 트리 구조를 뱉어내는 순수 UI 함수 작성.
Core Topic 02: 상태(State)와 리컴포지션 엔진
- Why to Learn: 좋아요 버튼을 눌렀을 때, 프로필 사진은 놔두고 오직 하트 아이콘만 재빨리 다시 그리도록 렌더링 범위를 통제하기 위함입니다.
- What to Learn:
mutableStateOf,remember, 리컴포지션(Recomposition), 스마트 건너뛰기(Skips). - How to Learn: 최상위 함수에 상태가 있고 자식 함수 A(상태 안 씀), B(상태 씀)가 있을 때, 상태가 변하면 부모와 B만 재실행되고 A는 스킵(Skip)당하는 로그(Log)를 찍어 리컴포지션 최적화를 눈으로 목격합니다.
- Implement: 타이머나 텍스트 입력창을 구현할 때, 변수 선언에
remember { mutableStateOf("") }를 붙여 화면이 새로고침(Recompose)되더라도 변숫값이 소멸되지 않고 캐시되는 메모리 방어 로직 구현.
Recommended
Core Topic 03: 상태 호이스팅과 렌더링 성능 (State Hoisting & Stability)
- Why to Learn: 버튼 컴포넌트가 혼자 상태를 쥐고 있으면 다른 화면에서 재사용할 수 없으므로, 재사용 가능한 레고 블록(Stateless)을 깎기 위해서입니다.
- What to Learn: State Hoisting(상태 끌어올리기), Stateless Composable, Stable/Immutable 타입 어노테이션,
derivedStateOf. - How to Learn: 스위치 컴포넌트 내부에 있던
isOn상태를 뜯어내서 부모에게 넘기고, 자신은 오직(isOn: Boolean, onToggle: () -> Unit)이라는 매개변수만 받아 작동하는 멍청한(Stateless) 컴포넌트로 개조하는 구조적 진화를 스케치합니다. - Implement: 리스트 스크롤 위치 데이터를 부모 컴포넌트로 호이스팅하고, 스크롤이 '맨 밑에 닿았는지(Boolean)'만
derivedStateOf로 감싸 필터링함으로써 픽셀 스크롤마다 발생하는 무의미한 리컴포지션 폭격을 막아내는 최적화 적용.
7. Terminology
8. References
Primary References
- [CS2023: HCI / Software Engineering] — 반응형(Reactive) UI 프로그래밍 패러다임 및 단방향 데이터 흐름(UDF).
- [SWEBOK v3: Software Design] — 함수형 렌더링 아키텍처, 부수 효과(Side Effect) 고립 및 상태-뷰(State-View) 의존성 역전.
Secondary References
- [Jetpack Compose Compiler Architecture] —
@Composable람다의 상태 방출(Emitting), Positional Memoization 물리학. - [Thinking in Compose] — 명령형(Imperative) 객체 변이 구조에서 선언형(Declarative) 상태 투영(Projection)으로의 철학적 전환.
Industry References
- [Android Developer: Lifecycle and State in Compose] — 스마트 리컴포지션 스킵(Skip) 알고리즘과 Stable/Immutable 타입 추론 물리.
- [Android Developer: Side-effects in Compose] —
LaunchedEffect,DisposableEffect를 통한 비동기 작업 생명주기 바인딩.
9. Final Checklist
Primary Checklist
- 상태(State) 변경 시 트리 전체가 아닌, 해당 상태를 잃고 있는 특정
@Composable함수만 스마트하게 재실행(Recomposition)되도록 설계했는가? - 하위 컴포넌트 내부에 상태를 숨겨두지 않고, 부모 컴포넌트로 상태를 끌어올려(State Hoisting) 재사용 가능한 순수(Stateless) UI 블록을 만들었는가?
Secondary Checklist
- 컴포저블 함수 내부에서 직접 코루틴을 열어 네트워크를 호출하는 등 렌더링 부수 효과(Side Effect)를 일으키지 않고,
LaunchedEffect안에 안전하게 격리했는가? - 스크롤 오프셋(Offset)처럼 초당 60번씩 변하는 상태 값을 UI 로직에 직결하여 앱을 마비시키는 대신,
derivedStateOf로 임계점(Threshold)만 필터링하여 렌더링을 방어했는가?
Industry Checklist
- 리스트나 복잡한 애니메이션 UI를 그릴 때, Android Studio의 Layout Inspector를 활용하여 리컴포지션 횟수(Count)가 폭주하는 병목 구간을 눈으로 탐지했는가?
- 컴파일러가 상태 변화를 추적하지 못하는 불안정(Unstable) 클래스(예: 일반
var필드가 있는 모델)로 인해 재렌더링 스킵(Skip)이 실패하는 문제를@Stable또는@Immutable로 해결했는가?
태그
native-android-physics-mechanicsjetpack-compose-recomposition-physicsmobilecross-platform-physicsmechanicsnative-android-physicsjetpackcomposerecompositionphysicscrossmobile-uiframework-mechanics