Какой жизненный цикл у ViewModel?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Жизненный цикл ViewModel в Android
Жизненный цикл ViewModel — это одна из фундаментальных концепций архитектуры Android Jetpack, которая отличает его от жизненного цикла Activity или Fragment. ViewModel специально разработан для хранения и управления UI-данными, связанными с конфигурационными изменениями (например, поворот экрана), обеспечивая сохранность данных при таких событиях.
Ключевые аспекты жизненного цикла ViewModel
1. Создание и время жизни
ViewModel создается, когда впервые запрашивается в пределах scope (области видимости) — обычно через ViewModelProvider в Activity или Fragment. Он остается в памяти до тех пор, пока его scope полностью не уничтожится:
- Для Activity — до вызова
Activity.onDestroy(), если уничтожение не вызвано конфигурационными изменениями. - Для Fragment — до полного уничтожения Fragment (не при detach/reattach).
- Для Navigation Graph, BackStackEntry и других пользовательских scope — в соответствии с их жизненным циклом.
// Пример получения ViewModel в Activity
class MainActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ViewModel создается здесь при первом вызове viewModel
}
}
2. Сохранение при конфигурационных изменениях
Главная особенность — ViewModel не уничтожается при повороте экрана или других конфигурационных изменениях. Система сохраняет ссылку на существующий экземпляр и повторно использует его для новой Activity/Fragment:
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
init {
// Этот код выполнится только одинжды при создании,
// даже если Activity пересоздастся при повороте
loadData()
}
}
3. Методы жизненного цикла ViewModel
ViewModel имеет собственные callback-методы:
- onCleared() — вызывается непосредственно перед уничтожением ViewModel, когда его scope полностью завершается (например, Activity завершается или Fragment удаляется из back stack). Здесь следует освобождать ресурсы, отменять корутины, закрывать соединения:
class MyViewModel : ViewModel() {
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.Main + job)
fun fetchData() {
scope.launch {
// Загрузка данных
}
}
override fun onCleared() {
super.onCleared()
job.cancel() // Важно: отмена корутин при очистке
// Закрытие других ресурсов
}
}
4. Сравнение с жизненным циклом Activity/Fragment
Визуально взаимосвязь можно представить так:
Activity Lifecycle: onCreate() → onStart() → onResume() → onPause() → onStop() → onDestroy()
↗ (поворот экрана) → Повторение onCreate()...
ViewModel Lifecycle: created → ----------------- active ------------------→ onCleared()
Ключевые отличия:
- ViewModel переживает конфигурационные изменения, а Activity/Fragment — нет
- ViewModel очищается только при окончательном уничтожении host-компонента
- ViewModel не имеет прямого доступа к контексту Activity (во избежание утечек памяти)
5. Best Practices и предупреждения
- Не храните ссылки на View, Context или Activity в ViewModel — это вызывает утечки памяти.
- Используйте AndroidViewModel, если нужен Application Context (для доступа к ресурсам, системным сервисам).
- Логика данных в ViewModel, логика отображения в UI-контроллерах — четкое разделение ответственности.
- LiveData/StateFlow в ViewModel + наблюдение в UI — стандартный паттерн для реактивного UI.
- Тестирование — ViewModel легко тестируется отдельно от Android-компонентов.
Заключение
Жизненный цикл ViewModel — это продвинутый механизм сохранения состояния UI-данных, который позволяет создавать устойчивые к изменениям конфигурации приложения с чистой архитектурой. Понимание этого жизненного цикла критически важно для предотвращения утечек памяти, правильного управления ресурсами и создания отзывчивых Android-приложений. ViewModel не является заменой onSaveInstanceState() — эти механизмы дополняют друг друга: ViewModel для больших наборов данных, переживающих поворот экрана, а SavedStateHandle для небольших критичных данных, нужных при полном уничтожении процесса.