Кто и когда вызывает метод onCleared у ViewModel
Что проверяют
Знаете ли вы механику, а не формулу «когда экран уничтожен». Интервьюеру важно услышать, что ViewModel переживает поворот экрана и почему. Следом обычно спрашивают, вызовется ли onCleared() при смерти процесса и что к этому моменту уже случилось с viewModelScope.
Как отвечать
Сам разработчик onCleared() не вызывает. Цепочка такая: владелец хранилища (ViewModelStoreOwner) вызывает ViewModelStore.clear(), тот проходит по своим ViewModel и у каждой вызывает внутренний clear(), а уже он в конце зовёт onCleared().
Кто и когда очищает хранилище:
- Activity:
ComponentActivityподписана на свойLifecycleи наON_DESTROYочищает хранилище, только еслиisChangingConfigurations()вернулfalse. Поворот экрана или смена темы ViewModel не трогают, аfinish()или кнопка «назад» очищают; - Fragment: хранилище фрагмента очищает
FragmentManager, когда фрагмент уничтожается окончательно, например удалён транзакцией или снят с back stack, а не пересоздаётся из-за конфигурации; - Navigation: ViewModel, привязанная к
NavBackStackEntryили к графу черезnavGraphViewModels, живёт, пока запись или граф лежат в back stack. ПослеpopBackStack()их хранилище очищается; - Compose:
viewModel()берёт ближайшегоViewModelStoreOwner, поэтому время жизни задаёт Activity, фрагмент или запись навигации, а не composable.
Внутренний clear() сначала закрывает всё, что зарегистрировано через addCloseable(), включая viewModelScope, и только потом вызывает onCleared(). В onCleared() освобождают то, что не закрылось само: слушателей, колбэки сторонних SDK, ручные подписки.
Где спотыкаются
Повторяют «вызывается, когда отписался последний наблюдатель». Это путаница с LiveData.onInactive(), к жизненному циклу ViewModel наблюдатели отношения не имеют.
Думают, что onCleared() гарантирован. При убийстве процесса системой не вызывается ничего, данные для восстановления нужно класть в SavedStateHandle.
Запускают в onCleared() корутину через viewModelScope.launch, чтобы что-то сохранить напоследок. Скоуп к этому моменту уже отменён, и код не выполнится.