Кто вызывает коллбэк onSavedStateHandle
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Отличный, очень глубокий и правильный вопрос. Он затрагивает сердце современной архитектуры Android, связывая компоненты ViewModel, SavedStateHandle и жизненный цикл.
Если говорить коротко: коллбэк onSaveInstanceState() (и, следовательно, механизм сохранения состояния в SavedStateHandle) вызывается системой Android (ОС) в строго определённых условиях жизненного цикла активности (Activity) или фрагмента (Fragment).
Давайте разберём всю цепочку вызовов детально, от высокоуровневого триггера до конкретного коллбэка.
Основной принцип и триггер
Система Android вызывает Activity.onSaveInstanceState() (или Fragment.onSaveInstanceState()) перед тем, как уничтожить компонент для освобождения ресурсов, но с намерением восстановить его позже. Классические сценарии:
- Поворот устройства (смена конфигурации).
- Переход приложения в фон, когда система может убить процесс для экономии памяти.
- Переход на другую активность в том же task, когда текущая может быть уничтожена.
Это системный, платформенный вызов. Разработчик не вызывает его напрямую.
Цепочка делегирования от Activity к ViewModel
В современном подходе с ViewModel и SavedStateHandle мы не переопределяем onSaveInstanceState() вручную. Вместо этого мы используем абстракции, которые автоматически интегрируются в этот жизненный цикл. Вот как это работает:
- Система ->
Activity.onSaveInstanceState(Bundle outState).
Система вызывает этот метод и предоставляет пустой `Bundle` (`outState`).
- Activity ->
FragmentManager.saveAllState().
Активность делегирует сохранение состояния своим фрагментам через `FragmentManager`.
- Для каждого Fragment ->
Fragment.onSaveInstanceState(Bundle outState).
Если фрагмент имеет `ViewModel` (через `ViewModelProvider`), `FragmentManager` и система `ViewModel` вступают в сговор.
- Ключевое звено:
SavedStateViewModelFactoryиSavedStateHandleController.
Когда вы создаёте `ViewModel` с помощью `ViewModelProvider`, и используете стандартную фабрику (или `by viewModels()` в фрагменте), под капотом работает специальный компонент — **`SavedStateViewModelFactory`**. Он создаёт `ViewModel` и привязывает к нему объект **`SavedStateHandle`**.
В момент вызова `Fragment.onSaveInstanceState()` происходит следующее:
```kotlin
// Упрощённая логика внутри платформы/библиотеки lifecycle-viewmodel-savedstate
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// Для каждого ViewModel, связанного с этим фрагментом...
savedStateRegistryController.performSave(outState)
// ^ Этот вызов проходит через цепочку, в конце которой
// состояние из SavedStateHandle каждого ViewModel записывается в Bundle.
}
```
5. SavedStateHandle -> Сохранение в Bundle.
Объект `SavedStateHandle` внутри себя содержит `MutableLiveData` или подобные структуры для ключей, которые вы в него положили (через `set()` или `getLiveData()`). В момент `performSave()` все эти ключи и их **сериализуемые** значения (`String`, `Int`, `Parcelable` и т.д.) записываются в тот самый `Bundle`, который система передала в `onSaveInstanceState()`.
А что с onSavedStateHandle?
Важно уточнить: прямого коллбэка с именем onSavedStateHandle не существует. Возможно, вопрос имел в виду один из двух аспектов:
1. Процесс сохранения состояния в SavedStateHandle
Это не коллбэк, а автоматический процесс, описанный выше. Вы, как разработчик, просто кладёте данные в SavedStateHandle через его методы, и система позже сама их сериализует.
class MyViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
init {
// Сохраняем значение. Оно будет автоматически записано в Bundle.
savedStateHandle.set("USER_ID_KEY", 12345)
// Получаем LiveData. Её значение будет автоматически восстановлено из Bundle.
val userIdLiveData = savedStateHandle.getLiveData<Int>("USER_ID_KEY")
}
}
2. Процесс восстановления состояния из SavedStateHandle
Когда активность/фрагмент создаётся заново (например, после поворота), система передаёт сохранённый Bundle в метод onCreate().
- Для
Activity:onCreate(savedInstanceState: Bundle?). - Для
Fragment:onCreate(savedInstanceState: Bundle?).
Далее, при создании ViewModel через ViewModelProvider, SavedStateViewModelFactory принимает этот Bundle, распаковывает его и наполняет данными новый экземпляр SavedStateHandle, который затем передаётся в конструктор ViewModel.
// ViewModel создаётся так:
ViewModelProvider(this, defaultViewModelProviderFactory).get(MyViewModel::class.java)
// Под капотом фабрика делает примерно это:
class SavedStateViewModelFactory(...) {
fun create(modelClass: String): ViewModel {
val savedStateHandle = createSavedStateHandle(bundleFromOnCreate) // <-- Бандл здесь!
return MyViewModel(savedStateHandle) // Передаём хэндл в конструктор
}
}
Таким образом, в момент создания ViewModel после восстановления, её SavedStateHandle уже содержит все ранее сохранённые значения. Вы можете прочитать их сразу в init блоке или подписаться на LiveData.
Итог
- Первичный инициатор — операционная система Android, управляющая жизненным циклом.
- Триггер — вызов системой метода
onSaveInstanceState()уActivity/Fragment. - Механизм — инфраструктура Jetpack (
lifecycle-viewmodel-savedstate), которая перехватывает этот вызов, сериализует содержимое всехSavedStateHandle, связанных с компонентом, в системныйBundle, и затем восстанавливает из него при повторном создании. - Роль разработчика — использовать
SavedStateHandleкак чёрный ящик для хранения критических для восстановления данных, не вмешиваясь в ручное управлениеBundle. Вся магия происходит автоматически благодаря правильной инициализацииViewModelчерезViewModelProvider.