Как сохранить данные при повороте экрана в Activity
Что проверяют
Понимаете ли вы, что поворот это изменение конфигурации, при котором Activity уничтожается и создаётся заново, и какой механизм переживает только поворот, а какой ещё и смерть процесса. Следом почти всегда спрашивают: «А если система убьёт процесс, пока приложение в фоне?»
Как отвечать
Разложите состояние по типам и для каждого назовите место хранения:
ViewModel: переживает изменение конфигурации, потому что живёт вViewModelStore, который при пересоздании не уничтожается. Сюда идут загруженные данные, состояние экрана, корутины вviewModelScope. Смерть процессаViewModelне переживает;SavedStateHandle: приходит в конструкторViewModelи сохраняется вBundle, поэтому переживает и поворот, и смерть процесса. Подходит для небольших значений: идентификатор, поисковый запрос, выбранная вкладка;onSaveInstanceState(Bundle): классический способ на уровнеActivity. Восстанавливают вonCreate, проверивsavedInstanceStateнаnull, или вonRestoreInstanceState, который вызывается послеonStart;- стандартные
Viewсandroid:id:EditTextи другие виджеты сохраняют своё состояние сами; - Compose:
rememberтеряет значение при повороте,rememberSaveableсохраняет, в том числе после смерти процесса; - постоянные данные: всё, что живёт дольше экрана, уходит в Room или DataStore, а не в
Bundle.
У Bundle есть предел: он проходит через Binder, и при большом объёме вы получите TransactionTooLargeException, поэтому держите в нём десятки килобайт, не больше.
Смерть процесса проверяется опцией разработчика «Не сохранять действия» или командой adb shell am kill <пакет> для приложения в фоне.
Где спотыкаются
Предлагают android:configChanges="orientation|screenSize" как основное решение. Пересоздание отключается, но обработка конфигурации ложится на вас, а при смерти процесса состояние всё равно теряется.
Считают, что ViewModel решает всё. После убийства процесса она создаётся заново, и без SavedStateHandle пользователь теряет введённое.
Кладут в Bundle целые списки или Bitmap и ловят TransactionTooLargeException на реальных устройствах.