Какие знаешь способы хранения текущего состояния экрана?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы хранения текущего состояния экрана в Android
В Android существует несколько ключевых подходов к сохранению состояния экрана, каждый из которых решает разные сценарии: от временного хранения данных при повороте устройства до постоянного сохранения пользовательского прогресса. Вот основные методы:
1. ViewModel
ViewModel — это компонент архитектуры Android, предназначенный для хранения и управления UI-данными жизненно-независимым способом. Он переживает изменения конфигурации (например, поворот экрана), но уничтожается при окончательном завершении активити/фрагмента.
class UserViewModel : ViewModel() {
private val _userName = MutableLiveData<String>()
val userName: LiveData<String> = _userName
fun updateName(name: String) {
_userName.value = name
}
}
// Использование в Activity/Fragment
class MyActivity : AppCompatActivity() {
private lateinit var viewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
viewModel.userName.observe(this) { name ->
// Обновление UI
}
}
}
2. Сохранение состояния через onSaveInstanceState()
Этот механизм позволяет сохранить небольшой объем данных (сериализуемых в Bundle) при временном уничтожении активити (из-за нехватки памяти или изменения конфигурации). Данные восстанавливаются в onCreate() или onRestoreInstanceState().
class MainActivity : AppCompatActivity() {
private var currentScore: Int = 0
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("SCORE_KEY", currentScore)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
currentScore = savedInstanceState.getInt("SCORE_KEY", 0)
}
}
}
3. Сохранение состояния в Fragment (setRetainInstance)
Устаревший способ, где фрагмент не пересоздавался при изменении конфигурации. Вместо него теперь рекомендуется использовать ViewModel вместе с SavedStateHandle.
4. SavedStateHandle в ViewModel
Расширение ViewModel, позволяющее сохранять состояние даже при полном уничтожении процесса приложения (системой для освобождения памяти).
class SavedStateViewModel(
private val state: SavedStateHandle
) : ViewModel() {
companion object {
private const val SEARCH_QUERY_KEY = "query"
}
val query: LiveData<String> = state.getLiveData(SEARCH_QUERY_KEY)
fun setQuery(query: String) {
state.set(SEARCH_QUERY_KEY, query)
}
}
5. Персистентное хранение
Для долговременного сохранения состояния между сессиями приложения используются:
- SharedPreferences — для простых ключ-значение данных
- Базы данных (Room) — для структурированных данных
- DataStore — современная замена SharedPreferences с поддержкой Kotlin Coroutines/Flow
- Файловая система — для сложных объектов или больших данных
// Пример с DataStore
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
class SettingsRepository(private val dataStore: DataStore<Preferences>) {
val userPreferencesFlow: Flow<UserPreferences> = dataStore.data
.map { preferences ->
UserPreferences(
darkMode = preferences[PreferencesKeys.DARK_MODE] ?: false
)
}
suspend fun updateDarkMode(enabled: Boolean) {
dataStore.edit { preferences ->
preferences[PreferencesKeys.DARK_MODE] = enabled
}
}
}
6. Архитектурные подходы
- MVI (Model-View-Intent) — состояние экрана описывается единым иммутабельным объектом
- StateFlow/SharedFlow в сочетании с ViewModel для реактивного управления состоянием
class NewsViewModel : ViewModel() {
private val _uiState = MutableStateFlow(NewsUiState())
val uiState: StateFlow<NewsUiState> = _uiState.asStateFlow()
data class NewsUiState(
val isLoading: Boolean = false,
val articles: List<Article> = emptyList(),
val error: String? = null
)
}
Критерии выбора подхода
- Временное состояние при повороте → ViewModel
- Восстановление после убийства процесса → ViewModel + SavedStateHandle или onSaveInstanceState()
- Долговременное хранение между запусками → DataStore, Room, SharedPreferences
- Комплексное UI-состояние → StateFlow в ViewModel или MVI
- Навигационные аргументы → Safe Args или сохранение в ViewModel
Практические рекомендации
- Избегайте хранения больших объектов (битмапы, списки) в Bundle — используйте идентификаторы и перезагружайте данные
- Разделяйте ответственность: UI-состояние — во ViewModel, постоянные данные — в репозиториях
- Тестируйте сценарии с убийством процесса (можно включить опцию "Don't keep activities" в настройках разработчика)
- Для навигации между фрагментами передавайте минимально необходимые идентификаторы, а не сложные объекты
Современный рекомендуемый стек: ViewModel + SavedStateHandle для управления состоянием жизненного цикла, StateFlow для реактивного UI, DataStore для простых постоянных данных и Room для структурированного хранения. onSaveInstanceState() остается полезным для краевых случаев, когда ViewModel еще не инициализирована в ранних этапах жизненного цикла.