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

Jetpack Compose에서 remember와 rememberSaveable 비교

skydovesJaewoong Eum (skydoves)||8분 소요

Jetpack Compose에서 remember와 rememberSaveable 비교

Jetpack Compose는 일반적인 리컴포지션(Recomposition) 과정에서는 동일하게 동작하지만, 시스템이 컴포저블의 호스트를 소멸시키고 다시 생성할 때 서로 다르게 동작하는 두 가지 상태 유지 메커니즘을 제공합니다. remember는 단일 컴포지션 수명 내에서 리컴포지션이 발생해도 상태를 유지하며, rememberSaveable은 여기서 한 걸음 더 나아가 구성 변경(configuration change)이나 프로세스 종료(process death) 상황에서도 상태를 saved instance state Bundle에 기록하여 영속적으로 보존합니다. 각 메커니즘이 언제 상태를 폐기하는지, 그리고 커스텀 Saver를 활용하여 rememberSaveable을 어떻게 확장할 수 있는지 이해하는 것은 안드로이드 생명주기를 올바르게 처리하는 UI를 구축하는 데 필수적입니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.

  • remember가 컴포지션의 슬롯 테이블(slot table)에 값을 저장하는 방식과 해당 값이 소실되는 시점을 설명할 수 있습니다.
  • rememberSaveable이 saved instance state 메커니즘과 어떻게 통합되는지 서술할 수 있습니다.
  • rememberSaveable이 기본적으로 저장할 수 있는 타입과 커스텀 타입을 지원하는 방법을 파악할 수 있습니다.
  • Bundle에 직접 담을 수 없는 객체를 영속화하기 위한 Saver를 직접 구현할 수 있습니다.
  • 상태의 수명 요구사항에 따라 rememberrememberSaveable 중 적절한 것을 선택할 수 있습니다.

remember의 동작 원리

remember는 Compose 런타임의 슬롯 테이블(slot table)에 값을 저장합니다. 슬롯 테이블은 각 컴포저블 호출에 대한 상태와 컴포지션 노드를 추적하는 내부 데이터 구조입니다. 컴포저블이 컴포지션에 처음 진입하면 remember 블록이 실행되어 결과를 저장하고, 이후 리컴포지션에서는 런타임이 슬롯 테이블에서 저장된 값을 읽어 블록을 다시 실행하지 않고 그대로 반환합니다. 다음 예제를 통해 기본적인 사용법을 확인할 수 있습니다.

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

저장된 값은 해당 컴포저블이 컴포지션 트리에 존재하는 한 리컴포지션을 거쳐도 유지됩니다. 하지만 컴포저블이 컴포지션을 벗어나는 경우(예를 들어, 조건 분기에 의해 제거되는 경우)나 호스트 Activity가 소멸되는 경우에는 함께 폐기됩니다. 화면 회전과 같은 구성 변경은 Activity를 소멸시킨 뒤 재생성하므로, 전체 컴포지션 트리와 모든 remember 값이 함께 사라지게 됩니다. 이 점이 remember의 가장 중요한 한계이며, 면접에서도 자주 질문되는 포인트입니다.

슬롯 테이블은 영속 계층(persistence layer)이 없는 순수 메모리 내 구조입니다. Composition 객체가 존재하는 동안에만 유효하며, 이 객체는 ComposeViewsetContent 호출의 생명주기에 종속됩니다. 따라서 remember는 재계산이 가능하거나 재생성 이후에는 의미가 없는 일시적 상태(transient state)에 적합합니다.

rememberSaveable의 동작 원리

rememberSaveableremember를 확장하여, 저장된 값을 SaveableStateRegistry에 등록합니다. SaveableStateRegistry는 Compose가 안드로이드의 saved instance state 메커니즘과 연동하는 통합 지점(integration point)입니다. 시스템이 구성 변경이나 프로세스 종료 전에 상태를 저장해야 할 때, 레지스트리는 등록된 값들을 Bundle로 직렬화하여 ActivityFragment의 saved instance state에 첨부합니다. 다음은 검색 바에 rememberSaveable을 적용한 예제입니다.

@Composable
fun SearchBar() {
    var query by rememberSaveable { mutableStateOf("") }
    TextField(
        value = query,
        onValueChange = { query = it }
    )
}

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

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

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