← Назад к вопросам

До какого момента ViewModel гарантирует сохранение состояния

2.0 Middle🔥 162 комментариев
#Жизненный цикл и навигация

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

ViewModel и жизненный цикл: гарантии сохранения состояния

ViewModel в Android Architecture Components не сохраняет своё состояние автоматически в том смысле, как это делает, например, Activity при вызове onSaveInstanceState(). Однако её ключевая гарантия заключается в том, что она переживает изменение конфигурации устройства (например, поворот экрана, изменение языка, размера окна в multi-window режиме). Это её основная и главная цель.

Границы "жизни" ViewModel и гарантии

Гарантия сохранения состояния ViewModel действует с момента её создания и до момента окончательного уничтожения владеющего ей компонента (Activity, Fragment, Navigation graph), но ТОЛЬКО ЕСЛИ это уничтожение НЕ связано с изменением конфигурации.

  1. Гарантировано сохранение при:
    *   **Повороте экрана.**
    *   **Изменении языка/локали.**
    *   **Изменении размера окна** (переход в multi-window режим).
    *   **Любом другом событии,** которое приводит к уничтожению и повторному созданию Activity/Fragment системой Android, но при котором сама логическая "жизнь" компонента не завершена.

  1. НЕ гарантировано сохранение при:
    *   **Явном завершении 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

Рекомендуемая стратегия:

  1. Основные UI-данные (загруженные списки, выбранные фильтры) храните в ViewModel.
  2. Минимальные идентификаторы для восстановления этих данных (например, userId, searchQuery) сохраняйте через SavedStateHandle.
  3. Исходные данные (сетевые ответы, профили пользователей) сохраняйте в базе данных (Room).
  4. Состояние навигации и сложные UI-состояния (позиция скролла в RecyclerView) обрабатывайте с помощью специализированных компонентов (Navigation, onSaveInstanceState View).