Как правильно сохранять состояние компонентов в Jetpack Compose
Когда мы разрабатываем приложения с использованием Jetpack Compose, особенно для мобильных устройств, где часто происходят изменения конфигурации (например, поворот экрана), важно правильно сохранять состояние компонентов. В Android классические подходы использовали методы вроде onSaveInstanceState()
и ViewModel
, чтобы сохранять состояние UI, но в Compose есть более удобные и эффективные инструменты для этих целей.
Когда пользователь взаимодействует с приложением, его действия, такие как ввод текста, нажатия кнопок, выбор переключателей и прочее, должны быть сохранены при изменении конфигурации устройства (например, поворот экрана) или при выходе из приложения. Без сохранения состояния приложение будет сбрасываться к начальному состоянию, что ухудшает пользовательский опыт.
remember
и rememberSaveable
ViewModel
mapSaver
и listSaver
remember
и rememberSaveable
Compose предлагает функцию remember
, которая используется для запоминания значения между пересозданиями UI. Однако, она не сохраняет данные при изменении конфигурации. Для этого предназначена функция rememberSaveable
, которая сохраняет состояние даже при изменении конфигурации (например, поворот экрана).
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text(text = "Count: $count")
}
}
В этом примере значение count
запоминается при пересоздании UI (например, из-за изменения данных), но не сохраняется при изменении конфигурации.
@Composable
fun Counter() {
var count by rememberSaveable { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text(text = "Count: $count")
}
}
Теперь, если повернуть экран, значение count
останется таким, каким оно было до изменения конфигурации.
rememberSaveable
?ViewModel
Для более сложных сценариев, где состояние должно быть связано с данными или бизнес-логикой, лучше использовать ViewModel
. Состояние, управляемое через ViewModel
, сохраняется даже при уничтожении и пересоздании Activity
или Fragment
.
class CounterViewModel : ViewModel() {
var count by mutableStateOf(0)
private set
fun increment() {
count++
}
}
@Composable
fun Counter(viewModel: CounterViewModel = viewModel()) {
Button(onClick = { viewModel.increment() }) {
Text(text = "Count: ${viewModel.count}")
}
}
Здесь состояние count
управляется через ViewModel
, что гарантирует его сохранение при любых изменениях конфигурации.
ViewModel
?mapSaver
и listSaver
Когда нужно сохранить более сложные типы данных (например, объекты), которые не могут быть сохранены напрямую через rememberSaveable
, можно использовать mapSaver
или listSaver
.
data class User(val name: String, val age: Int)
val userSaver = mapSaver(
save = { mapOf("name" to it.name, "age" to it.age) },
restore = { User(it["name"] as String, it["age"] as Int) }
)
@Composable
fun UserProfile() {
val user = rememberSaveable(stateSaver = userSaver) { User("John", 30) }
Column {
Text(text = "Name: ${user.name}")
Text(text = "Age: ${user.age}")
}
}
В этом примере используется mapSaver
для сохранения и восстановления объекта User
. Мы сохраняем значения полей объекта в карту, а затем восстанавливаем их при необходимости.
mapSaver
или listSaver
?