Compose에서 상태 복원
rememberSavable
API는 저장된 인스턴스 상태 메커니즘을 사용하여 recomposition
과 activity
전반에 걸쳐 상태를 유지하므로 remember
과 비슷하게 작동합니다.
remember
과 가장 큰 차이점은 rememberSavable
는 Bundle
에 값을 저장하지 때문에 화면회전이 발생할 때 값이 초기화되지 않습니다.
상태를 저장하는 방법
Bundle
에 추가되는 모든 데이터 타입은 자동으로 저장됩니다. Bundle
에 추가할 수 없는 항목을 저장하려는 경우 몇 가지 옵션이 있습니다.
Parcelize
가장 간단한 방법은 객체에 @Parcelize
어노테이션을 추가하는 것입니다. 그러면 객체가 parcelable
이 되며 번들로 저장될 수 있습니다.
Parcelable : Parcel에 의해 쓰이고 복구될 수 있는 클래스를 위한 인터페이스를 말한다.
Parcel : IBinder를 통해 보내질 수 있는 메시지 컨테이너이다.
IBinder : 프로세스 내 호출과 프로세스 간 호출을 수행할 때 고성능을 위해 설계된 경량 원격 프로시저 호출 메커니즘의 핵심 부분인 원격 개체에 대한 기본 인터페이스입니다
모듈단 build.gradle
에 plugins
를 추가해 줍니다.
plugins {
id("kotlin-parcelize")
}
간단한 샘플 코드입니다
@Parcelize
data class City(val name: String, val country: String): Parcelable
@Composable
fun ParcelizeSnippet(){
var selectedCity = rememberSaveable {
mutableStateOf(City("울산", "울산광역시"))
}
Text(text = selectedCity.value.country)
}
여기서 @Parcelize
를 붙이지 않고 rememberSavable
에 넣는다면 어떻게 될까요?
data class City(val name: String, val country: String)
@Composable
fun ParcelizeSnippet(){
var selectedCity = rememberSaveable {
mutableStateOf(City("울산", "울산광역시"))
}
Text(text = selectedCity.value.country)
}
java.lang.IllegalArgumentException: MutableState containing City(name=울산, country=울산광역시) cannot be saved using the current SaveableStateRegistry. The default implementation only supports types which can be stored inside the Bundle. Please consider implementing a custom Saver for this class and pass it as a stateSaver parameter to rememberSaveable().
저장할 수 없는 타입이므로 customSaver
를 쓰거나 stateSaver
를 쓰도록 권장하는 경고 메시지를 볼 수 있습니다.
MapSaver
어떤 이유로 @Parcelize
가 적합하지 않을 경우, mapSaver
를 사용하여 객체를 집합으로 변환하여 시스템이 Bundle
에 저장할 수 있도록 고유한 규칙을 정의할 수 있습니다.
data class Region(val name: String, val country: String)
val RegionSaver = run{
//key 지정
val nameKey = "Name"
val countryKey = "Country"
mapSaver(
//bundle에 저장할 map의 key, value 할당
save = {mapOf(nameKey to it.name, countryKey to it.country)},
//bundle에서 복구할 때 방식을 지정
restore = {Region(it[nameKey] as String, it[countryKey] as String)}
)
}
@Composable
fun MapSaverSnippet(){
val selectedCity = rememberSaveable(stateSaver = RegionSaver) {
mutableStateOf(Region("Madrid", "울산"))
}
Text(text = selectedCity.value.toString())
}

listSaver
listSaver
를 사용하고 index
를 키로 사용하면 맵의 키를 정의할 필요가 없습니다.
val RegionSaver2 = listSaver<Region, Any>(
save = { listOf(it.name, it.country) },
restore = {Region(it[0] as String, it[1] as String)}
)
@Composable
fun ListSaverSnippet(){
val selectedCity = rememberSaveable(stateSaver = RegionSaver2) {
mutableStateOf(Region("울산", "광역시"))
}
Text(text = selectedCity.value.toString())
}

Compose의 상태 홀더
간단한 상태 끌어올리기(State Hoisting)는 Composable 함수 자체에서 관리 가능합니다만, 추적할 상태의 양이 늘어나거나 Composable 함수에서 별도로 실행해야 할 로직이 있는 경우 상태 홀더에 위임하는 것이 좋습니다.
대표적인 예시로 ViewModel
이 있습니다.
'안드로이드(Compose) > 개념' 카테고리의 다른 글
remember 강제 재실행하는 방법 (0) | 2024.04.11 |
---|---|
State Hoisting(상태 호이스팅) (0) | 2024.03.27 |
Stateful 과 Stateless (0) | 2024.03.25 |
지원되는 기타 State 유형 (0) | 2024.03.20 |
State and Jetpack Compose (0) | 2024.03.18 |