До какого момента ViewModel гарантирует сохранение состояния
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
ViewModel и жизненный цикл: гарантии сохранения состояния
ViewModel в Android Architecture Components не сохраняет своё состояние автоматически в том смысле, как это делает, например, Activity при вызове onSaveInstanceState(). Однако её ключевая гарантия заключается в том, что она переживает изменение конфигурации устройства (например, поворот экрана, изменение языка, размера окна в multi-window режиме). Это её основная и главная цель.
Границы "жизни" ViewModel и гарантии
Гарантия сохранения состояния ViewModel действует с момента её создания и до момента окончательного уничтожения владеющего ей компонента (Activity, Fragment, Navigation graph), но ТОЛЬКО ЕСЛИ это уничтожение НЕ связано с изменением конфигурации.
- Гарантировано сохранение при:
* **Повороте экрана.**
* **Изменении языка/локали.**
* **Изменении размера окна** (переход в multi-window режим).
* **Любом другом событии,** которое приводит к уничтожению и повторному созданию Activity/Fragment системой Android, но при котором сама логическая "жизнь" компонента не завершена.
- НЕ гарантировано сохранение при:
* **Явном завершении Activity:** когда пользователь нажимает кнопку "Назад" или вызывается `finish()`.
* **Завершении процесса системой:** при нехватке памяти в фоне (Process death).
* **Уничтожении Fragment** с помощью `FragmentTransaction.remove()` и без добавления в back stack, если ViewModel была привязана к этому Fragment.
Механизм работы и ограничения
ViewModel сохраняется благодаря тому, что хранится в ViewModelStore, который принадлежит компоненту. При изменении конфигурации уничтожается View (Activity/Fragment), но объект ViewModelStore сохраняется системой и передаётся вновь созданному экземпляру компонента.
// ViewModel сохранит значение counter при повороте экрана
class MyViewModel : ViewModel() {
private var _counter = MutableLiveData(0)
val counter: LiveData<Int> get() = _counter
fun increment() {
_counter.value = _counter.value?.plus(1)
}
}
// В Activity
class MyActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// При повороте экрана здесь будет возвращён ТОТ ЖЕ экземпляр ViewModel
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
viewModel.counter.observe(this) { value ->
// Значение будет восстановлено
textView.text = "Count: $value"
}
}
}
Что НЕ входит в гарантии ViewModel?
Важно понимать, что ViewModel — не серебряная пуля для всех сценариев. Для полного сохранения состояния UI необходимо комбинировать несколько подходов:
-
Для Process Death: Используйте SavedStateHandle (интеграция с
onSaveInstanceState). Это позволяет сохранить критически важные данные (ID, простые типы) в Bundle системы.class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() { companion object { private const val USER_ID_KEY = "USER_ID_KEY" } var userId: String get() = savedStateHandle[USER_ID_KEY] ?: "" set(value) = savedStateHandle.set(USER_ID_KEY, value) } -
Для сложных или объёмных данных: Используйте постоянное хранилище (Room Database, DataStore, SharedPreferences). ViewModel должна загружать такие данные из репозитория, который, в свою очередь, работает с persistent-источником.
-
Для навигации: Состояние навигации (например, текущий экран) лучше делегировать Navigation Component или сохранять в SavedStateHandle.
Вывод и лучшие практики
Таким образом, ViewModel гарантирует сохранение своего состояния в памяти только на протяжении "логической" жизни компонента владельца, пока она не будет явно завершена пользователем или системой. Её жизненный цикл можно представить так:
Создание ViewModel -> [Изменение конфигурации] -> [Изменение конфигурации] -> ... -> Окончательное уничтожение владельца (не из-за конфигурации) -> onCleared() -> Уничтожение ViewModel
Рекомендуемая стратегия:
- Основные UI-данные (загруженные списки, выбранные фильтры) храните в ViewModel.
- Минимальные идентификаторы для восстановления этих данных (например,
userId,searchQuery) сохраняйте через SavedStateHandle. - Исходные данные (сетевые ответы, профили пользователей) сохраняйте в базе данных (Room).
- Состояние навигации и сложные UI-состояния (позиция скролла в RecyclerView) обрабатывайте с помощью специализированных компонентов (Navigation,
onSaveInstanceStateView).