면접 질문 목록으로 가기
면접 질문실전 질문꼬리 질문

Jetpack Compose의 리컴포지션(Recomposition)

skydovesJaewoong Eum (skydoves)||8분 소요

Jetpack Compose의 리컴포지션(Recomposition)

리컴포지션(Recomposition)은 Jetpack Compose에서 입력 상태(state)가 변경되었을 때 컴포저블(composable) 함수를 다시 실행하는 과정입니다. Compose 런타임은 전체 UI 트리를 처음부터 다시 구성하지 않고, 어떤 컴포저블 함수가 어떤 상태 객체를 읽었는지 추적하여 입력이 변경된 함수만 선택적으로 다시 호출합니다. 이러한 선택적 업데이트 메커니즘을 스마트 리컴포지션(smart recomposition)이라 하며, Compose 성능 모델의 핵심 원리입니다. 면접에서 리컴포지션의 동작 원리를 정확히 설명할 수 있다면 Compose에 대한 깊은 이해를 보여줄 수 있으므로, 꼭 숙지해 두시길 권장합니다.

이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.

  • Compose 런타임이 상태 읽기를 추적하고 리컴포지션을 트리거하는 원리를 설명할 수 있습니다.
  • remember, mutableStateOf, derivedStateOf가 상태 관리에서 각각 어떤 역할을 하는지 이해할 수 있습니다.
  • 리컴포지션 과정에서 컴포저블 함수가 건너뛰기(skippable) 가능한 조건이 무엇인지 파악할 수 있습니다.
  • 불필요한 리컴포지션을 최소화하기 위한 모범 사례(best practices)를 적용할 수 있습니다.
  • 컴파일러 리포트와 Layout Inspector를 활용하여 리컴포지션 성능 문제를 진단할 수 있습니다.

리컴포지션의 동작 원리

컴포저블 함수는 한 번 호출된 뒤 잊히는 것이 아닙니다. Compose 런타임은 슬롯 테이블(slot table)이라는 자료 구조를 유지하며, 각 컴포저블 호출의 현재 상태와 출력을 저장합니다. 상태 객체가 변경되면 런타임은 해당 상태를 읽은 모든 컴포저블을 유효하지 않은(invalid) 상태로 표시하고, 다음 프레임에서 이 유효하지 않은 컴포저블만 다시 실행합니다. 이 과정이 바로 리컴포지션의 핵심 메커니즘입니다.

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Column {
        Text("Count: $count")
        Button(onClick = { count++ }) {
            Text("Increase")
        }
    }
}

버튼을 클릭하면 count 값이 변경됩니다. 런타임은 Text("Count: $count") 컴포저블이 count를 읽었다는 사실을 알고 있으므로, 해당 부분의 트리만 다시 실행합니다. Button 컴포저블과 그 내부의 라벨 Textcount를 직접 읽지 않기 때문에, 런타임이 입력값의 변경 여부를 판단하여 리컴포지션을 건너뛸 수 있습니다.

런타임은 슬롯 테이블을 활용하여 이전 값과 현재 값을 비교합니다. 컴포저블의 입력이 변경되지 않았고 컴파일러에 의해 건너뛰기 가능(skippable)으로 표시되어 있다면, 해당 서브트리의 리컴포지션은 완전히 생략됩니다. 이것이 바로 Compose가 수많은 컴포넌트로 구성된 복잡한 UI에서도 효율적으로 동작하는 이유입니다. 실제로 변경된 상태에 의존하는 부분만 다시 실행되므로, 불필요한 연산을 최소한으로 줄일 수 있습니다.

remembermutableStateOf를 활용한 상태 추적

mutableStateOf는 Compose 런타임이 관찰할 수 있는 상태 객체를 생성합니다. 컴포저블 함수가 실행 도중 이 상태를 읽으면 런타임은 해당 의존성을 기록하고, 상태 값이 변경되면 기록된 모든 읽기 대상을 무효화합니다.

remember는 값을 슬롯 테이블에 저장하여 리컴포지션이 일어나도 값을 유지합니다. remember 없이 mutableStateOf를 사용하면 리컴포지션이 발생할 때마다 새로운 상태 객체가 생성되어 현재 값이 초기화되는 문제가 발생합니다. 이는 면접에서 자주 등장하는 핵심 포인트이므로 반드시 숙지하셔야 합니다.

// 올바른 사용: 상태가 리컴포지션 이후에도 유지됨
var text by remember { mutableStateOf("") }

// 잘못된 사용: 리컴포지션마다 상태가 초기화됨
var text by mutableStateOf("")

이 면접 질문은 구독자 전용입니다

Dove Letter를 구독하시면 안드로이드, 코틀린 개발 관련 독점 면접 질문의 전체 내용을 볼 수 있습니다.

구독하기
면접 질문 목록으로 가기