Как ViewModel может пережить поворот экрана
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Сохранение состояния с помощью ViewModel
ViewModel — это компонент архитектуры Android, специально разработанный для хранения и управления UI-данными, связанными с жизненным циклом. Его ключевая особенность — способность переживать изменения конфигурации, такие как поворот экрана. Это достигается не за счет сохранения самого объекта, а через механизм повторного использования, управляемый системой.
Как это работает: жизненный цикл и хранилище
-
Создание и привязка к жизненному циклу: ViewModel создается с помощью
ViewModelProvider, который привязывает экземпляр ViewModel к конкретному LifecycleOwner (например, Fragment или Activity). Провайдер хранит ViewModel в специальном хранилище. -
Использование
ViewModelStore: За кулисами существует объектViewModelStore, который содержит коллекцию (например,HashMap) ViewModel'ей. Каждому LifecycleOwner (Activity или Fragment) соответствует свойViewModelStore. -
Ключевая роль
ComponentActivity: При повороте экрана Activity уничтожается и создается заново. Однако, если ваш Activity наследуется отComponentActivity(илиAppCompatActivity, которая его расширяет), егоViewModelStoreне уничтожается системой при изменении конфигурации. Вместо этого хранилище передается новому экземпляру Activity. -
Повторное использование: Когда новый экземпляр Activity запрашивает ViewModel того же типа и с тем же ключом (обычно это класс активити или фрагмента),
ViewModelProviderсначала проверяетViewModelStoreстарого экземпляра. Если там есть подходящая ViewModel, она возвращается новому владельцу жизненного цикла. Таким образом, объект ViewModel не уничтожается и не пересоздается, а данные в нем сохраняются.
// Пример получения ViewModel в Activity. При повороте экрана
// будет возвращен тот же экземпляр `MyViewModel`.
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ViewModelProvider использует бэкенд (ViewModelStore) для
// поиска существующего или создания нового экземпляра.
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
// Начинаем наблюдать за LiveData. При повороте экрана подписка
// будет автоматически пересоздана, но сама LiveData и ее значение
// сохранятся в ViewModel.
viewModel.data.observe(this) { data ->
// Обновляем UI с сохраненными данными
}
}
}
Преимущества подхода ViewModel
- Автоматическое управление: Вам не нужно вручную обрабатывать
onSaveInstanceState()для простых данных UI (хотя для навигации или критичных данных это все еще нужно). - Эффективность: Сохраняются тяжелые объекты (списки, сетевые ответы), которые нецелесообразно сериализовать в Bundle.
- Разделение ответственности: UI-контроллер (Activity/Fragment) отвечает только за отображение данных и обработку ввода, а бизнес-логика и данные живут в ViewModel.
Важные нюансы и ограничения
- ViewModel НЕ переживает полное уничтожение процесса. Если система убьет приложение из-за нехватки памяти, все ViewModel'и будут уничтожены. Для восстановления состояния в этом случае используйте
onSaveInstanceState()в сочетании с ViewModel илиSavedStateHandle. SavedStateHandle— это современный способ сохранять в ViewModel минимально необходимые данные (ID, простые типы) для восстановления после смерти процесса. Он интегрирован в ViewModel.
class MyViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
// Сохраняем и читаем данные через SavedStateHandle.
// Они переживут и поворот экрана, и смерть процесса.
var userId: String
get() = savedStateHandle["userId"] ?: ""
set(value) = savedStateHandle.set("userId", value)
// Остальные "тяжелые" данные, которые не нужны для
// немедленного восстановления, можно хранить просто как свойства.
val userData: LiveData<User> = ...
}
- Не храните контексты в ViewModel! ViewModel живет дольше, чем UI-контроллер. Хранение ссылки на Activity, View или Context, привязанный к Activity, приведет к утечке памяти. Если нужен Context, используйте
AndroidViewModel, который предоставляет Application Context.
Таким образом, ViewModel переживает поворот экрана благодаря тому, что система сохраняет его хранилище (ViewModelStore) и передает его новому экземпляру UI-контроллера, обеспечивая целостность данных и улучшая пользовательский опыт.