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

Как сохранить состояние экрана при смене конфигурации устройства с помощью ViewModel

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

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

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

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

Сохранение состояния экрана при смене конфигурации с помощью ViewModel

При смене конфигурации устройства (поворот экрана, изменение языка, подключение клавиатуры) система Android по умолчанию уничтожает и заново создает Activity/Fragment. Это приводит к потере данных, которые хранились в UI-компонентах. ViewModel — это компонент архитектуры Android, предназначенный для хранения и управления UI-данными, связанными с жизненным циклом, способный пережить такие изменения конфигурации.

Основные принципы работы ViewModel

ViewModel сохраняется при изменении конфигурации благодаря своей связи с LifecycleOwner (обычно Activity или Fragment) через ViewModelProvider. Когда владелец уничтожается и воссоздается из-за смены конфигурации, ViewModel остается в памяти, и новый экземпляр владельца получает ссылку на тот же объект ViewModel. Это происходит потому, что ViewModel хранится в ViewModelStore, который ассоциирован с контекстом приложения, а не с конкретным экземпляром Activity.

Реализация с использованием ViewModel

Рассмотрим практический пример. Допустим, у нас есть счетчик, значение которого не должно сбрасываться при повороте экрана.

1. Создание класса ViewModel:

import androidx.lifecycle.ViewModel

class CounterViewModel : ViewModel() {
    private var _counter = 0
    val counter: Int get() = _counter
    
    fun increment() {
        _counter++
    }
}

2. Использование ViewModel во Fragment (или Activity):

import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
import androidx.fragment.app.Fragment

class MyFragment : Fragment() {
    private lateinit var viewModel: CounterViewModel
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // Инициализация ViewModel
        viewModel = ViewModelProvider(this).get(CounterViewModel::class.java)
        
        // Наблюдение за изменениями счетчика
        viewModel.counter.observe(viewLifecycleOwner) { count ->
            textView.text = "Count: $count"
        }
        
        // Обработка клика для увеличения счетчика
        button.setOnClickListener {
            viewModel.increment()
        }
    }
}

Ключевые преимущества подхода

  • Автоматическое сохранение состояния: ViewModel переживает смену конфигурации без дополнительного кода.
  • Разделение ответственности: Логика данных отделена от UI-логики, что соответствует принципам чистой архитектуры.
  • Предотвращение утечек памяти: ViewModel автоматически очищается, когда связанный с ней LifecycleOwner полностью уничтожается (не из-за смены конфигурации).
  • Совместимость с LiveData/StateFlow: ViewModel идеально сочетается с наблюдаемыми компонентами для реактивного UI.

Важные ограничения и дополнения

  1. ViewModel НЕ переживает завершение процесса: Для сохранения данных между полным завершением приложения необходимо использовать SavedStateHandle или постоянное хранилище.

  2. Использование SavedStateHandle:

class CounterViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    companion object {
        private const val COUNTER_KEY = "counter_key"
    }
    
    val counter = savedStateHandle.getLiveData<Int>(COUNTER_KEY, 0)
    
    fun increment() {
        val current = counter.value ?: 0
        savedStateHandle.set(COUNTER_KEY, current + 1)
    }
}
  1. Не храните ссылки на View/Context: ViewModel переживает View, поэтому хранение ссылок на контекст Activity может вызвать утечки памяти. Используйте Application Context, если необходим контекст.

Рекомендуемая архитектура с ViewModel

Fragment/Activity (UI Layer)
         ↓ (наблюдает)
     ViewModel (Business Logic Layer)
         ↓ (использует)
   Repository (Data Layer)
         ↓
   Data Sources (Local/Remote)

ViewModel становится центральным компонентом для управления состоянием UI, обеспечивая стабильность данных при любых изменениях конфигурации устройства, при этом соблюдая принципы чистого разделения кода и эффективного управления памятью.