Состояние вне remember и его последствия
Разбираем классическую ошибку новичков: состояние без remember и без rememberSaveable, и чем это грозит.
rememberSaveable — версия remember, которая дополнительно сохраняет значение при пересоздании Activity (поворот экрана, восстановление процесса).
Три уровня «памяти» состояния
Важно различать три варианта объявления состояния и понимать, что выживает в каждом:
// 1) Сбросится при ЛЮБОЙ перерисовке
var a = mutableStateOf(0)
// 2) Переживёт recomposition, но НЕ поворот экрана
var b by remember { mutableStateOf(0) }
// 3) Переживёт и recomposition, и поворот экрана
var c by rememberSaveable { mutableStateOf(0) }| Способ | Переживает recomposition | Переживает поворот |
| без remember | нет | нет |
remember | да | нет |
rememberSaveable | да | да |
Что ломается без remember
Состояние без remember пересоздаётся при каждой перерисовке, возвращаясь к начальному значению. Счётчик, объявленный так, никогда не вырастет — UI будет упорно показывать ноль. Это одна из самых частых ошибок при первом знакомстве с Compose.
Когда нужен rememberSaveable
Поворот экрана пересоздаёт Activity и саму композицию — обычный remember при этом теряет значение. Для пользовательского ввода (текст в поле, выбранная вкладка, позиция) используйте rememberSaveable: он сохраняет данные в Bundle и восстанавливает после пересоздания.
@Composable
fun Form() {
var name by rememberSaveable { mutableStateOf("") }
TextField(value = name, onValueChange = { name = it })
}Без rememberSaveable пользователь повернул бы телефон — и весь введённый текст исчез. С ним — текст на месте.
Как работает под капотом
rememberSaveable кладёт значение в механизм сохранённого состояния (saved instance state), который система использует при пересоздании Activity. Поэтому туда можно класть только сохраняемые типы (примитивы, строки, Parcelable); для сложных объектов нужен кастомный Saver. Долгоживущее же состояние экрана (загруженные данные) обычно держат не здесь, а в ViewModel.
Частые ошибки
- Объявить состояние без
rememberи не понимать, почему счётчик «не считает». - Использовать
rememberтам, где данные обязаны пережить поворот — после поворота ввод теряется. - Класть в
rememberSaveableкрупные несохраняемые объекты вместоViewModel.
Итог
- Состояние без
rememberсбрасывается на каждой перерисовке — частая причина «несчитающего» счётчика. rememberпереживает recomposition, но не поворот экрана.rememberSaveableпереживает и поворот; долгоживущие данные держите вViewModel.