Как восстановить состояние после изменения конфигурации?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Восстановление состояния после изменения конфигурации в Android
Восстановление состояния приложения после изменения конфигурации (например, поворота устройства, изменения языка или размера окна в многозадачном режиме) — одна из ключевых задач разработчика Android. При изменении конфигурации система уничтожает текущий Activity или Fragment и создает новый, что приводит к потере текущего состояния. Для корректной работы приложения необходимо правильно сохранять и восстанавливать данные.
Механизмы сохранения состояния
1. onSaveInstanceState() и Bundle
Основной метод для сохранения легковесного состояния в Activity и Fragment. Система автоматически вызывает его перед уничтожением. Сохраненные данные передаются новому экземпляру через Bundle в методах onCreate() или onRestoreInstanceState().
class MainActivity : AppCompatActivity() {
private var currentScore = 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)
}
}
}
2. ViewModel
Класс ViewModel специально разработан для управления данными, связанными с UI, и не уничтожается при изменении конфигурации. Это самый рекомендуемый современный подход для сохранения состояния.
class GameViewModel : ViewModel() {
private var _score = MutableLiveData(0)
val score: LiveData<Int> = _score
fun increaseScore() {
_score.value = _score.value?.plus(1)
}
}
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: GameViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this).get(GameViewModel::class.java)
viewModel.score.observe(this, Observer { score ->
updateScoreUI(score)
})
}
}
3. Persistent Storage
Для сохранения важных данных (настройки пользователя, прогресс игры) следует использовать постоянное хранилище:
- SharedPreferences для простых ключ-значение.
- Local Database (Room, SQLite) для структурированных данных.
- Files или Cloud Storage.
// Использование SharedPreferences
val prefs = getSharedPreferences("APP_PREFS", MODE_PRIVATE)
fun saveHighScore(score: Int) {
prefs.edit().putInt("HIGH_SCORE", score).apply()
}
fun loadHighScore(): Int {
return prefs.getInt("HIGH_SCORE", 0)
}
Стратегии восстановления UI состояния
Для сложных UI компонентов:
- Идентификаторы View с
android:id: система автоматически сохраняет и восстанавливает состояние View с ID (например, текст в EditText). - Сохранение состояния в Fragment через
onSaveInstanceState()или аргументы (arguments).
class MyFragment : Fragment() {
private var listState: Bundle? = null
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
recyclerView.layoutManager?.onSaveInstanceState()?.let {
outState.putParcelable("LIST_STATE", it)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
savedInstanceState?.getParcelable<Parcelable>("LIST_STATE")?.let {
recyclerView.layoutManager?.onRestoreInstanceState(it)
}
}
}
Обработка объектов, не поддерживающих Parcelable:
Для сложных объектов можно использовать сериализацию или сохранять ключевые идентификаторы для последующей перезагрузки из источника данных.
Рекомендации и лучшие практики
- Разделение ответственности: легковесное UI состояние — в Bundle/ViewModel, важные данные — в Persistent Storage.
- Избегайте сохранения крупных объектов (Bitmap, большие коллекции) в Bundle — это может привести к превышению лимита размера.
- Для конфигураций, зависящих от данных, используйте ViewModel в сочетании с Repository для перезагрузки данных после recreation.
- Установка
android:configChangesдля определенных конфигураций позволяет предотвратить recreation Activity, но это требует самостоятельной обработки изменений и обычно рекомендуется только для специфичных случаев (например, камера).
<!-- В AndroidManifest.xml -->
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize">
</activity>
После объявления необходимо переопределить метод onConfigurationChanged() в Activity.
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Программная адаптация к новой конфигурации
adjustLayoutForOrientation(newConfig.orientation)
}
Итог: Современный подход основан на сочетании ViewModel (для данных UI), автоматического сохранения состояния Views с ID, и Persistent Storage для критичных данных. Это обеспечивает стабильное, конфигурационно-независимое поведение приложения.