Jetpack Compose 상태 관리 정리

Bluewave·2025년 6월 19일

안드로이드

목록 보기
10/14
post-thumbnail

📌 1. remember vs rememberSaveable

remember

  • 컴포저블이 recomposition 될 때까지 값을 기억
  • 앱이 백그라운드로 갔다 돌아오거나 화면이 recreate 되면 값이 사라짐
  • 내부적으로는 ViewTree에 상태를 저장하지 않고, 메모리 내에서만 유지
val username = remember { mutableStateOf("") }

❗ recomposition에는 유지되지만, 화면 회전/프로세스 재시작 시 초기화됨


rememberSaveable

  • remember와 동일하지만, Bundle 또는 SavedStateHandle에 값 저장
  • 화면 회전, 프로세스 kill 후 복원 시에도 상태 유지
  • @Parcelize, 기본 타입(Int, String, Boolean 등) 저장 가능
val username = rememberSaveable { mutableStateOf("") }

📦 내부적으로 SavedStateRegistry에 데이터를 저장하여 복원 가능


🔍 주요 차이 요약

항목rememberrememberSaveable
recomposition✅ 유지됨✅ 유지됨
화면 회전❌ 초기화✅ 유지됨
앱 재시작❌ 초기화✅ 유지됨
저장 방식메모리Bundle(SavedStateHandle)
사용 예임시 상태사용자 입력, 설정 값 등 유지해야 할 값

📌 2. StateFlow란?

✅ 정의

  • Kotlin Coroutine 기반의 state holder이자 비동기 데이터 스트림
  • 항상 최신 상태 값 1개만 유지하며, 구독자가 있으면 실시간으로 값을 방출
  • LiveData의 대체재로 사용되며, Compose에서 상태 관찰에 최적화됨
val _uiState = MutableStateFlow("")
val uiState: StateFlow<String> = _uiState.asStateFlow()

📌 3. 왜 StateFlow 구독 위치가 중요할까?

💡 이유 1. lifecycle을 고려하지 않으면 메모리 누수 위험

  • View가 없어졌는데도 계속 collect 중이면 불필요한 연산 발생
  • 특히 화면 이동 많고 상태 많은 앱(LipIt!)에선 치명적

💡 이유 2. recomposition마다 collect 하면 버그 발생

  • collectAsState()를 잘못된 위치에 두면 UI가 매 recomposition마다 새 구독을 시작함
  • → 상태 꼬임, 중복 렌더링, 무한 재구성 가능성

✅ 권장 방법

val uiState by viewModel.uiState.collectAsStateWithLifecycle()
  • Jetpack Compose + Lifecycle 통합된 collectAsStateWithLifecycle() 사용
  • Compose UI 생명주기에 맞게 자동으로 collect 시작/중지

🧩 예시로 이해하기

LipIt! 프로젝트에서, 텍스트 모드 ↔ 보이스 모드 전환 시 UI는 바뀌었는데 상태는 꼬였던 문제 발생
remember가 화면 회전 시 초기화되어 있었고
StateFlow는 composable 안에서 바로 collect해서 재구성마다 꼬임 발생

🔧 해결:

  • rememberSaveable로 상태 저장 방식 변경
  • collectAsStateWithLifecycle() 사용하여 구독 위치 고정 및 lifecycle 대응

✅ 마무리 정리

항목핵심 요약
remember단기 상태 기억 (recomposition 범위 내)
rememberSaveable화면 회전/복원까지 유지되는 상태 저장
StateFlow최신 상태 1개를 흐름으로 관리하는 데이터 스트림
구독 위치lifecycle-aware 위치에서 collect해야 상태 꼬임/누수 방지
profile
Developer's Logbook

0개의 댓글