Я работал над платформой Android SDK, и немного неясно, как сохранить состояние приложения. Итак, учитывая этот незначительный повторный инструментарий примера «Hello, Android»:
package com.android.hello;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloAndroid extends Activity {
private TextView mTextView = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView = new TextView(this);
if (savedInstanceState == null) {
mTextView.setText("Welcome to HelloAndroid!");
} else {
mTextView.setText("Welcome back.");
}
setContentView(mTextView);
}
}
Я думал, что этого будет достаточно для самого простого случая, но он всегда отвечает первым сообщением, независимо от того, как я ухожу от приложения.
Я уверен, что решение так же просто, как переопределение onPause
или что-то в этом роде, но я копался в документации около 30 минут и не нашел ничего очевидного.
Ответы:
Вам необходимо переопределить
onSaveInstanceState(Bundle savedInstanceState)
и записать значения состояния приложения, которые вы хотите изменить, вBundle
параметр следующим образом:Bundle - это, по сути, способ хранения карты NVP («пара имя-значение»), и он будет передан,
onCreate()
а такжеonRestoreInstanceState()
туда, где вы затем извлечете значения из действия следующим образом:Или из фрагмента.
Обычно вы используете эту технику для хранения значений экземпляра для вашего приложения (выборки, несохраненный текст и т. Д.).
источник
onSaveInstanceState
практически бесполезным, за исключением случаев изменения ориентации экрана. Почти во всех других случаях вы никогда не можете положиться на него, и вам нужно будет вручную сохранить состояние вашего интерфейса в другом месте. Или предотвращение уничтожения вашего приложения путем переопределения поведения кнопки НАЗАД. Я не понимаю, почему они вообще так реализовали это. Совершенно не интуитивно. И вы не можете иметь этот Bundle, который система дает вам для сохранения чего-либо, кроме как в этом особом методе.View
с , которые были назначены идентификаторами . ИзonSaveInstanceState
документации: «Реализация по умолчанию заботится о большей части состояния пользовательского интерфейса для каждого экземпляра, вызываяonSaveInstanceState()
каждое представление в иерархии, имеющей идентификатор, и сохраняя идентификатор текущего сфокусированного представления (все из которых восстанавливается). по умолчанию реализацияonRestoreInstanceState(Bundle)
) "Он
savedInstanceState
предназначен только для сохранения состояния, связанного с текущим экземпляром Activity, например, текущей навигационной информацией или информацией о выборе, так что, если Android уничтожает и воссоздает Activity, он может вернуться, как это было раньше. Смотрите документацию дляonCreate
иonSaveInstanceState
Для более долгоживущего состояния рассмотрите возможность использования базы данных SQLite, файла или настроек. См. Сохранение постоянного состояния .
источник
Обратите внимание, что это НЕ безопасно использовать
onSaveInstanceState
иonRestoreInstanceState
для постоянных данных , в соответствии с документацией о состояниях активности в http://developer.android.com/reference/android/app/Activity.html .В документе говорится (в разделе «Жизненный цикл действия»):
Другими словами, поместите ваш код сохранения / восстановления для постоянных данных в
onPause()
иonResume()
!РЕДАКТИРОВАТЬ : Для дальнейшего уточнения, вот
onSaveInstanceState()
документация:источник
Мой коллега написал статью , описывающее состояние приложения на устройствах Android , включая объяснение по жизненному циклу деятельности и информации о состоянии, как хранить информацию о состоянии и сохранении состояния
Bundle
иSharedPreferences
и взглянуть на здесь .В статье рассматриваются три подхода:
Храните локальные переменные / данные управления пользовательским интерфейсом для времени жизни приложения (т.е. временно), используя пакет состояния экземпляра
Храните данные локальной переменной / управления пользовательским интерфейсом между экземплярами приложения (то есть постоянно), используя общие настройки
Сохранение экземпляров объекта в памяти между действиями в течение времени жизни приложения с использованием сохраненного экземпляра без конфигурации
источник
Это классический «гоча» разработки для Android. Здесь есть две проблемы:
Просматривая все эти темы, я подозреваю, что большую часть времени разработчики говорят об этих двух разных проблемах одновременно ... отсюда и вся путаница и сообщения о том, что «это не работает для меня».
Во-первых, чтобы прояснить «предполагаемое» поведение: onSaveInstance и onRestoreInstance хрупки и только для переходного состояния. Предполагаемое использование (afaict) состоит в том, чтобы обрабатывать Активный отдых, когда телефон поворачивается (изменение ориентации). Другими словами, предполагаемое использование - это когда ваша активность все еще логически «наверху», но все равно должна быть переоценена системой. Сохраненный Bundle не сохраняется вне процесса / memory / gc, поэтому вы не можете действительно полагаться на это, если ваша деятельность переходит в фоновый режим. Да, возможно, память вашей Деятельности переживет свое путешествие в фоновый режим и избежит GC, но это ненадежно (и не предсказуемо).
Поэтому, если у вас есть сценарий, в котором есть значимый «прогресс пользователя» или состояние, которое должно сохраняться между «запусками» вашего приложения, руководство должно использовать onPause и onResume. Вы должны выбрать и подготовить постоянный магазин самостоятельно.
НО - есть очень запутанная ошибка, которая усложняет все это. Подробности здесь:
http://code.google.com/p/android/issues/detail?id=2373
http://code.google.com/p/android/issues/detail?id=5277
По сути, если ваше приложение запускается с флагом SingleTask, а затем вы запускаете его из главного экрана или из меню запуска, то этот последующий вызов создаст НОВУЮ задачу ... у вас фактически будет два разных экземпляра вашего приложения. населяет один и тот же стек ... что очень странно и очень быстро. Кажется, это происходит, когда вы запускаете свое приложение во время разработки (например, из Eclipse или Intellij), поэтому разработчики часто сталкиваются с этим. Но также через некоторые механизмы обновления магазина приложений (так что это также влияет на ваших пользователей).
Я боролся с этими темами в течение нескольких часов, прежде чем понял, что моей главной проблемой была эта ошибка, а не предполагаемое поведение фреймворка. Отличная рецензия и
обходной путь(ОБНОВЛЕНИЕ: см. Ниже), кажется, от пользователя @kaciula в этом ответе:Поведение нажатия клавиши «Домой»
ОБНОВЛЕНИЕ Июнь 2013 : Несколько месяцев спустя я наконец нашел «правильное» решение. Вам не нужно управлять какими-либо флагами StarApp с сохранением состояния самостоятельно, вы можете обнаружить это из фреймворка и соответствующим образом внести залог. Я использую это в начале моего LauncherActivity.onCreate:
источник
onSaveInstanceState
вызывается, когда системе требуется память и убивает приложение. Он не вызывается, когда пользователь просто закрывает приложение. Поэтому я думаю, что состояние приложения также должно быть сохранено вonPause
Оно должно быть сохранено в какое-либо постоянное хранилище, напримерPreferences
илиSqlite
источник
Оба метода полезны и допустимы, и оба лучше всего подходят для различных сценариев:
onSaveInstanceState()
и,onRestoreInstanceState()
как правило, этого достаточно.Если вы сохраняете данные о состоянии в постоянном режиме, они могут быть перезагружены в
onResume()
или илиonCreate()
(или фактически при любом вызове жизненного цикла). Это может или не может быть желательным поведением. Если вы храните его в связке вInstanceState
, то он временный и подходит только для хранения данных для использования в том же «сеансе» пользователя (я использую термин «сеанс»), но не между «сеансами».Дело не в том, что один подход лучше другого, как и все, просто важно понять, какое поведение вам требуется, и выбрать наиболее подходящий подход.
источник
Насколько я понимаю, сохранение состояния - в лучшем случае клудж. Если вам нужно сохранить постоянные данные, просто используйте базу данных SQLite . Android делает это СООО легко.
Что-то вроде этого:
Простой звонок после этого
источник
Я думаю, что нашел ответ. Позвольте мне рассказать, что я сделал, простыми словами:
Предположим, у меня есть два действия: действие 1 и действие 2, и я перехожу от действия 1 к занятию 2 (я выполнил некоторые работы в занятии 2) и снова возвращаюсь к занятию 1, нажав кнопку в занятии 1. Теперь на этом этапе я хотел вернуться к занятию2 и хочу, чтобы мое занятие2 было в том же состоянии, когда я последний раз оставлял занятие2.
Для описанного выше сценария я сделал несколько изменений, подобных этому:
И в активности1 на событие нажатия кнопки я сделал так:
И в активности 2 на событие нажатия кнопки я сделал так:
Теперь произойдет то, что любые изменения, которые мы внесли в действие 2, не будут потеряны, и мы сможем просмотреть действие 2 в том же состоянии, в котором мы вышли ранее.
Я считаю, что это ответ, и это прекрасно работает для меня. Поправь меня, если я ошибаюсь.
источник
onSaveInstanceState()
для временных данных (восстанавливается вonCreate()
/onRestoreInstanceState()
),onPause()
для постоянных данных (восстанавливается вonResume()
). Из технических ресурсов Android:источник
Действительно
onSaveInstanceState()
вызывается, когда активность переходит в фоновый режим.Цитата из документа: «Этот метод вызывается до того, как действие может быть прекращено, чтобы, когда оно вернется в будущем, оно могло восстановить свое состояние». Источник
источник
Чтобы помочь уменьшить шаблон, я использую следующее
interface
иclass
для чтения / записиBundle
для сохранения состояния экземпляра.Сначала создайте интерфейс, который будет использоваться для аннотирования переменных вашего экземпляра:
Затем создайте класс, в котором отражение будет использоваться для сохранения значений в пакете:
Пример использования:
Примечание. Этот код был адаптирован из библиотечного проекта AndroidAutowire, лицензированного по лицензии MIT .
источник
Между тем я вообще больше не пользуюсь
Жизненный цикл для большинства видов деятельности слишком сложен и не нужен.
И Google заявляет о себе, это даже не надежно.
Мой способ заключается в том, чтобы сохранить любые изменения сразу в настройках:
В некотором смысле SharedPreferences работают аналогично Bundles. И естественно и сначала такие значения должны быть прочитаны из предпочтений.
В случае сложных данных вы можете использовать SQLite вместо предпочтений.
При применении этой концепции действие просто продолжает использовать последнее сохраненное состояние, независимо от того, было ли это начальным открытием с промежуточными перезагрузками или повторным открытием из-за заднего стека.
источник
Чтобы ответить на оригинальный вопрос напрямую. saveInstancestate имеет значение null, поскольку ваша активность никогда не создается заново.
Ваша активность будет воссоздана только с помощью пакета состояний, когда:
Android будет уничтожать фоновые действия, когда они находятся под давлением памяти или после того, как они находились в фоновом режиме в течение длительного периода времени.
При тестировании вашего примера "Привет, мир" есть несколько способов уйти и вернуться к занятию.
В большинстве случаев, если вы просто нажимаете «Домой», а затем снова запускаете приложение, повторное создание действия не требуется. Он уже существует в памяти, поэтому onCreate () вызываться не будет.
В разделе «Настройки» -> «Параметры разработчика» есть опция «Не сохранять действия». Когда он включен, Android всегда уничтожает действия и воссоздает их, когда они находятся в фоновом режиме. Это отличный вариант, чтобы оставить включенным при разработке, потому что он имитирует худший сценарий. (Устройство с низким объемом памяти постоянно перерабатывает ваши действия).
Другие ответы ценны тем, что они учат вас правильным способам сохранения состояния, но я не чувствую, что они действительно ответили ПОЧЕМУ ваш код не работал так, как вы ожидали.
источник
onSaveInstanceState(bundle)
ИonRestoreInstanceState(bundle)
методы могут быть использованы для сохраняемости данных только при вращении экрана (изменение ориентации).Они даже не хорошо , а переключение между приложениями (поскольку
onSaveInstanceState()
метод вызываются , ноonCreate(bundle)
иonRestoreInstanceState(bundle)
не вызывается снова.Для большего использования сохранения общих предпочтений. Читать эту статью
источник
onCreate
иonRestoreInstanceState
неActivity
вызывается, потому что при переключении приложений вообще не уничтожается, поэтому не нужно ничего восстанавливать. Android вызываетonSaveInstanceState
на тот случай, если действие будет уничтожено позже (что происходит со 100% -ной уверенностью при повороте экрана, потому что изменилась вся конфигурация устройства, и действие должно быть воссоздано с нуля).Моя проблема заключалась в том, что мне требовалось постоянство только в течение жизненного цикла приложения (т. Е. Одно выполнение, включая запуск других вложенных действий в том же приложении, вращение устройства и т. Д.). Я пробовал различные комбинации приведенных выше ответов, но не получал то, что хотел во всех ситуациях. В конце концов, мне удалось получить ссылку на saveInstanceState во время onCreate:
и использовать это для получения содержимого моей переменной, когда мне это нужно, в соответствии с:
Я использую
onSaveInstanceState
иonRestoreInstanceState
как предложено выше, но я думаю, что я мог бы также или альтернативно использовать мой метод для сохранения переменной, когда она изменяется (например, используяputBoolean
)источник
Хотя принятый ответ правильный, существует более быстрый и простой способ сохранить состояние «Активность» на Android с помощью библиотеки « Icepick» . Icepick - это процессор аннотаций, который заботится обо всем шаблоне кода, который используется для сохранения и восстановления состояния за вас.
Делать что-то вроде этого с Icepick:
Это то же самое, что делать это:
Icepick будет работать с любым объектом, который сохраняет свое состояние с помощью
Bundle
.источник
Когда действие создается, вызывается метод onCreate ().
saveInstanceState - это объект класса Bundle, который является нулевым в первый раз, но он содержит значения при его воссоздании. Чтобы сохранить состояние действия, вы должны переопределить onSaveInstanceState ().
поместите ваши значения в объект Bundle "outState", например, outState.putString ("key", "Welcome Back") и сохраните, вызвав super. Когда активность будет уничтожена, ее состояние будет сохранено в объекте Bundle и может быть восстановлено после воссоздания в onCreate () или onRestoreInstanceState (). Пакет, полученный в onCreate () и onRestoreInstanceState (), одинаков.
или
источник
Есть два основных способа реализовать это изменение.
onSaveInstanceState()
иonRestoreInstanceState()
.android:configChanges="orientation|screenSize"
.Я действительно не рекомендую использовать второй метод. Так как в одном из моих опытов это приводило к тому, что половина экрана устройства становилась черной при повороте из портретного положения в ландшафтное и наоборот.
Используя первый метод, упомянутый выше, мы можем сохранить данные при изменении ориентации или при любом изменении конфигурации. Я знаю способ, которым вы можете хранить любой тип данных внутри объекта состояния saveInstance.
Пример: рассмотрим случай, если вы хотите сохранить объект Json. создать класс модели с геттерами и сеттерами.
Теперь в вашей деятельности в методах onCreate и onSaveInstanceState выполните следующие действия. Это будет выглядеть примерно так:
источник
Вот комментарий из ответа Стива Мозли (от ToolmakerSteve ), который показывает, что все в перспективе (в целом onSaveInstanceState против onPause, восточная стоимость против западной стоимости сага)
источник
Код Котлина:
спасти:
а затем в
onCreate()
илиonRestoreInstanceState()
Добавьте значения по умолчанию, если вы не хотите иметь дополнительные
источник
Чтобы получить данные о состоянии активности, сохраненные в
onCreate()
, сначала вы должны сохранить данные в saveInstanceState с помощью переопределенногоSaveInstanceState(Bundle savedInstanceState)
метода.Когда вызывается
SaveInstanceState(Bundle savedInstanceState)
метод уничтожения активности, и вы сохраняете данные, которые хотите сохранить. И вы получаете то же самоеonCreate()
при перезапуске активности. (SaveInstanceState не будет нулевым, так как вы сохранили в нем некоторые данные до уничтожения активности)источник
Просто быстро решить эту проблему с помощью IcePick
Сначала настройте библиотеку в
app/build.gradle
Теперь давайте проверим этот пример ниже, как сохранить состояние в Activity
Это работает для Деятельностей, Фрагментов или любого объекта, который должен сериализовать свое состояние в Пакете (например, ViewPresenters в ступке)
Icepick также может генерировать код состояния экземпляра для пользовательских видов:
источник
Не уверен, что мое решение осуждается или нет, но я использую связанный сервис для сохранения состояния ViewModel. Храните ли вы его в памяти в службе или сохраняете и извлекаете из базы данных SQLite, зависит от ваших требований. Это то, что делают сервисы любого типа, они предоставляют такие сервисы, как поддержание состояния приложения и абстрактную общую бизнес-логику.
Из-за ограничений памяти и обработки, присущих мобильным устройствам, я отношусь к представлениям Android аналогично веб-странице. Страница не поддерживает состояние, это просто компонент уровня представления, единственной целью которого является представление состояния приложения и принятие пользовательского ввода. В последних тенденциях в архитектуре веб-приложений используется устаревший шаблон Модель, представление, контроллер (MVC), где страница представляет собой представление, данные домена являются моделью, а контроллер располагается за веб-службой. Тот же самый шаблон может использоваться в Android, когда View, ну ... View, модель - это данные вашего домена, а Controller реализован как служба, привязанная к Android. Всякий раз, когда вы хотите, чтобы представление взаимодействовало с контроллером, связывайте его при запуске / возобновлении и снимайте привязку при останове / паузе.
Этот подход дает вам дополнительный бонус в реализации принципа разделения интересов, заключающегося в том, что бизнес-логика всех ваших приложений может быть перенесена в ваш сервис, что сокращает дублирование логики в нескольких представлениях и позволяет представлению применять другой важный принцип проектирования, Single Responsibility.
источник
Котлин
Вы должны переопределить
onSaveInstanceState
иonRestoreInstanceState
сохранить и получить ваши переменные, которые вы хотите быть постояннымиГрафик жизненного цикла
Хранить переменные
Получить переменные
источник
Теперь Android предоставляет ViewModels для сохранения состояния, вы должны попытаться использовать это вместо saveInstanceState.
источник
Существует способ заставить Android сохранять состояния без реализации какого-либо метода. Просто добавьте эту строку в свой манифест в декларации активности:
Это должно выглядеть так:
Здесь вы можете найти более подробную информацию об этой собственности.
Рекомендуется, чтобы Android обрабатывал это для вас, чем ручная обработка.
источник
Что сохранить, а что нет?
Вы когда-нибудь задумывались, почему текст в
EditText
автоматически сохраняется при изменении ориентации? Ну, этот ответ для вас.Когда экземпляр Activity будет уничтожен, и система заново создаст новый экземпляр (например, изменение конфигурации). Он пытается воссоздать его, используя набор сохраненных данных старого состояния активности ( состояние экземпляра) ).
Состояние экземпляра - это набор пар ключ-значение, хранящихся в
Bundle
объекте.EditText
ListView
т. Д.Если вам нужно сохранить другую переменную как часть состояния экземпляра, вам следует переопределить
onSavedInstanceState(Bundle savedinstaneState)
метод.Например,
int currentScore
в GameActivityБолее подробная информация о onSavedInstanceState (Bundle saveinstaneState) при сохранении данных
Какой выбрать для восстановления состояния активности?
ИЛИ
Оба метода получают один и тот же объект Bundle, поэтому не имеет значения, где вы пишете логику восстановления. Единственное отличие состоит в том, что в
onCreate(Bundle savedInstanceState)
методе вы должны будете дать нулевую проверку, пока она не нужна в последнем случае. Другие ответы уже содержат фрагменты кода. Вы можете отослать их.Подробнее о onRestoreInstanceState (Bundle saveinstaneState)
бонус
Система
onSaveInstanceState(Bundle savedInstanceState)
вызывается только тогда, когда пользователь намеревается вернуться в действие. Например, вы используете приложение X и неожиданно получаете звонок. Вы перемещаетесь в приложение вызывающего абонента и возвращаетесь в приложение X. В этом случаеonSaveInstanceState(Bundle savedInstanceState)
метод будет вызван.Но учтите это, если пользователь нажимает кнопку «Назад». Предполагается, что пользователь не намерен возвращаться в действие, поэтому в этом случае система
onSaveInstanceState(Bundle savedInstanceState)
не будет вызываться. Вы должны учитывать все сценарии при сохранении данных.Соответствующие ссылки:
Демо по умолчанию поведения
Android Официальная документация .
источник
Теперь имеет смысл сделать 2 способа в представлении модели. если вы хотите сохранить первый как сохраненный экземпляр: вы можете добавить параметр состояния в модель представления, например, https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate#java
или вы можете сохранить переменные или объект в модели представления, в этом случае модель представления будет удерживать жизненный цикл до тех пор, пока действие не будет уничтожено.
источник
Вы можете использовать
Live Data
иView Model
для Lifecycle Handel
FromJetPack
. см. эту ссылку:https://developer.android.com/topic/libraries/architecture/livedata
источник