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

Как восстановить состояние после изменения конфигурации?

2.3 Middle🔥 191 комментариев
#Архитектура и паттерны

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

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

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

Восстановление состояния после изменения конфигурации в 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 для критичных данных. Это обеспечивает стабильное, конфигурационно-независимое поведение приложения.