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

Jetpack Compose의 SaveableStateHolder

skydovesJaewoong Eum (skydoves)||8분 소요

Jetpack Compose의 SaveableStateHolder

SaveableStateHolder는 고유 식별자를 키로 사용하여 컴포저블 하위 트리의 rememberSaveable 상태를 독립적으로 보존하고 복원하는 Compose 인터페이스입니다. rememberSaveable이 구성 변경(configuration changes) 시 개별 값을 유지하는 역할을 한다면, SaveableStateHolder는 저장 가능한 상태의 전체 범위(scope)를 관리합니다. 덕분에 내비게이션 시스템의 각 화면처럼 독립적인 생명주기를 갖는 컴포저블에 대해 상태를 저장, 제거, 복원할 수 있습니다. 면접에서 이 주제가 나오면 단순히 rememberSaveable과의 차이만 설명하는 것이 아니라, 내비게이션 상태 관리의 전체 그림을 이해하고 있음을 보여주는 것이 중요합니다.

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

  • SaveableStateHolder가 범위와 목적 면에서 rememberSaveable과 어떻게 다른지 설명할 수 있습니다.
  • SaveableStateProvider가 고유 키를 사용하여 컴포저블 하위 트리의 저장 가능한 상태를 어떻게 연결하는지 설명할 수 있습니다.
  • rememberSaveableStateHolder()를 활용하여 화면별 상태를 보존하는 내비게이션 시스템을 구축할 수 있습니다.
  • 상태를 SaveableStateHolder에 귀속시킬지, ViewModel에 귀속시킬지 판단하는 기준을 제시할 수 있습니다.
  • 컴포저블 하위 트리가 컴포지션에 진입하거나 이탈할 때 저장된 상태의 생명주기를 설명할 수 있습니다.
  • 영구적으로 폐기된 화면의 저장 상태를 제거하여 메모리를 관리하는 방법을 이해할 수 있습니다.

SaveableStateHolder의 동작 원리

SaveableStateHolderrememberSaveableStateHolder()를 통해 생성됩니다. 이 인터페이스는 SaveableStateProvider(key, content) 컴포저블을 제공하며, 해당 컴포저블은 하위 트리를 감싸면서 그 안에서 호출되는 모든 rememberSaveable을 지정된 키와 연결합니다. 하위 트리가 컴포지션에서 제거되더라도 상태는 홀더에 보존되며, 동일한 키로 하위 트리가 다시 추가되면 상태가 자동으로 복원됩니다.

@Composable
fun SimpleNavigation(currentRoute: String) {
    val stateHolder = rememberSaveableStateHolder()

    stateHolder.SaveableStateProvider(currentRoute) {
        when (currentRoute) {
            "home" -> HomeScreen()
            "settings" -> SettingsScreen()
        }
    }
}

사용자가 "home"에서 "settings"로 이동하면 HomeScreen 컴포저블이 컴포지션에서 제거됩니다. 일반적으로 HomeScreen 내부의 모든 rememberSaveable 상태는 이 시점에서 소실됩니다. 하지만 SaveableStateProvider("home")로 감싸져 있기 때문에, 상태 홀더가 해당 상태를 "home" 키 아래에 유지합니다. 사용자가 다시 "home"으로 돌아오면 SaveableStateProvider("home")가 저장된 상태를 모두 복원하므로, HomeScreen은 사용자가 떠나기 전과 완전히 동일한 상태로 표시됩니다. 이 메커니즘이 바로 화면 전환 시 스크롤 위치나 입력 내용이 유지되는 핵심 원리입니다.

고유 키를 활용한 상태 범위 지정

SaveableStateProvider에 전달하는 키는 상태 범위의 식별자 역할을 합니다. 각 고유 키는 독립적인 저장 상태 집합에 매핑되므로, 서로 다른 키를 가진 두 화면은 동일한 컴포저블 함수를 사용하더라도 완전히 별개의 상태를 유지합니다. 키는 equals()hashCode()가 올바르게 구현된 모든 타입을 사용할 수 있으며, 실무에서는 문자열이나 data class를 가장 많이 활용합니다.

키는 반드시 안정적이고 홀더 범위 내에서 고유해야 합니다. 리스트 인덱스를 키로 사용하면 항목 순서가 변경될 때 문제가 발생합니다. 예를 들어 위치 0에 저장되었던 상태가 순서 변경 후 위치 0을 차지하는 전혀 다른 항목에 복원되기 때문입니다. 이 부분은 LazyColumnkey 파라미터 설계 철학과도 일맥상통하므로, 면접에서 함께 언급하면 이해도가 높다는 인상을 줄 수 있습니다.

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

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

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