rememberval username = remember { mutableStateOf("") }
❗ recomposition에는 유지되지만, 화면 회전/프로세스 재시작 시 초기화됨
rememberSaveableremember와 동일하지만, Bundle 또는 SavedStateHandle에 값 저장@Parcelize, 기본 타입(Int, String, Boolean 등) 저장 가능val username = rememberSaveable { mutableStateOf("") }
📦 내부적으로 SavedStateRegistry에 데이터를 저장하여 복원 가능
| 항목 | remember | rememberSaveable |
|---|---|---|
| recomposition | ✅ 유지됨 | ✅ 유지됨 |
| 화면 회전 | ❌ 초기화 | ✅ 유지됨 |
| 앱 재시작 | ❌ 초기화 | ✅ 유지됨 |
| 저장 방식 | 메모리 | Bundle(SavedStateHandle) |
| 사용 예 | 임시 상태 | 사용자 입력, 설정 값 등 유지해야 할 값 |
LiveData의 대체재로 사용되며, Compose에서 상태 관찰에 최적화됨val _uiState = MutableStateFlow("")
val uiState: StateFlow<String> = _uiState.asStateFlow()
collectAsState()를 잘못된 위치에 두면 UI가 매 recomposition마다 새 구독을 시작함val uiState by viewModel.uiState.collectAsStateWithLifecycle()
collectAsStateWithLifecycle() 사용LipIt! 프로젝트에서, 텍스트 모드 ↔ 보이스 모드 전환 시 UI는 바뀌었는데 상태는 꼬였던 문제 발생
→ remember가 화면 회전 시 초기화되어 있었고
→ StateFlow는 composable 안에서 바로 collect해서 재구성마다 꼬임 발생
🔧 해결:
rememberSaveable로 상태 저장 방식 변경collectAsStateWithLifecycle() 사용하여 구독 위치 고정 및 lifecycle 대응| 항목 | 핵심 요약 |
|---|---|
| remember | 단기 상태 기억 (recomposition 범위 내) |
| rememberSaveable | 화면 회전/복원까지 유지되는 상태 저장 |
| StateFlow | 최신 상태 1개를 흐름으로 관리하는 데이터 스트림 |
| 구독 위치 | lifecycle-aware 위치에서 collect해야 상태 꼬임/누수 방지 |