Показаны сообщения с ярлыком putInt. Показать все сообщения
Показаны сообщения с ярлыком putInt. Показать все сообщения

9 апреля 2014 г.

Сохранение состояния Активности. Часть 2

Все таки еще немножко теории будет с альма-матер. Сделаю очень краткий и очень вольный перевод.

И еще немножко будет из этой статьи.

Существует несколько вариантов при которых ваша Активность может быть уничтожена в следствии естественного поведения приложения, например, если пользователь нажимает кнопку ОБРАТНО или же если ваша активность получает сигнал от метода finish(). Система так же может уничтожить вашу Активность если она в данный момент остановлена и не используется уже долгое время находясь в фоновом режиме. В этом случае если системе будут нужны ресурсы, она может уничтожить вашу Активность.

Когда Активность уничтожается естественным образом, например, если пользователь нажимает кнопку ОБРАТНО или же Активность уничтожает сама себя, система полагает что экземпляр Активности больше не нужен, так как это понятно из поведения самой Активности, и не запоминает ее состояние. Однако же, если система уничтожает Активность находящуюся в фоновом режиме, для высвобождения ресурсов, то система понимает, что состояние Активности надо сохранить, чтобы когда она будет создана заново, данные которые были в ней, вновь бы в ней отобразились. Сохраненные данные, которые система использует для восстановления состояния Активности, называются instance state, и они содержат пары в виде “ключ-значение” которые хранятся в объекте Bundle.

Примечание: Активность уничтожается и создается каждый раз, когда пользователь вращает экран устройства. Когда меняется ориентация экрана система уничтожает и создает Активность заново, это делается потому, что изменилась конфигурация экрана и возможно необходимо отобразить другую разметку (layout) и загрузить альтернативные ресурсы, которые могут отображаться только в этой ориентации экрана.

По умолчанию, система использует объект Bundle, чтобы сохранить состояние каждого View в разметке (layout), например текст введенный в поле EditText. Таким образом, если Активность уничтожается, то ее состояние восстанавливается АВТОМАТИЧЕCКИ и вам не надо писать для этого ни какой дополнительный код. Однако, ваша Активности может иметь какие-то дополнительные данные которые надо сохранять и восстанавливать, то в этом случае вам надо переопределить метод  onSaveInstanceState() для сохранения этих данных. При вызове этого метода система передает данные для сохранения в объект Bundle, который будет сохранен, даже если ваша Активность будет уничтожена. Когда же Активность создается, то она получает тот же объект Bundle в методах onCreate() и onRestoreInstanceState().

Еще раз напомним что для того чтобы система Андроид автоматически восстанавливала данные каждого View он должен иметь уникальный идентификатор ID, определяемый атрибутом android:id.

basic-lifecycle-savestate

На рисунке показано, что когда система начинает останавливать вашу Активность, то перед этим вызывается метод onSaveInstanceState() (1), в котором вы можете так же сохранить дополнительные нужные вам данные, которые затем можете восстановить когда Активность будет создана заново. После уничтожения Активности, когда ее экземпляр создается заново, система передает ей данные сохраненные на этапе (1) в методах  onCreate() (2) и onRestoreInstanceState() (3).

Сохранение состояния Активности

Когда ваша Активность останавливается системой, то вызывается метод onSaveInstanceState(), который сохраняет состояние Активности в наборе пар “ключ-значение”. По умолчанию этот метод сохраняет состояние всех View в layout, например текст введенный в поле EditText или же положение прокрутки в ListView. Чтобы сохранить дополнительные данные из вашей Активности вы должны переопределить метод   onSaveInstanceState() и добавить дополнительные пары “ключ-значение” в объект Bundle. Например:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

Внимание! Всегда вызывайте суперкласс метода onSaveInstanceState(), чтобы сохранить значение всех View.


Восстановление состояния Активности

Когда ваша активность воссоздаётся после того как была разрушена вы можете восстановить ее состояние из объекта Bundle, который система передает в вашу активность. Оба метода onCreate() и onRestoreInstanceState() при вызове получают один и тот же объект Bundle, содержащий информацию для восстановления состояния.

Поскольку метод onCreate() вызывается когда экземпляр вашей Активности создается заново, вы должны проверить состояние объекта Bundle на null, перед тем как пытаться прочитать из него данные. Если его состояние равно null, тогда система создаст новый экземпляр активности, а не будет восстанавливать предыдущий, который был уничтожен.

Пример восстановления состояния в методе onCreate():
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first
   
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}

Так же вы можете восстанавливать состояние Активности в методе onRestoreInstanceState(), который вызывается после метода onStart(). Система вызывает метод onRestoreInstanceState() только в том случае если имеются сохраненные данные для восстановления, поэтому нет ни какой необходимости проверять Bundle на null. Например:
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);
   
    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Внимание! Всегда вызывайте суперкласс метода onRestoreInstanceState(), чтобы сохранить значение всех View.

Далее попрактикуемся в этом чуть больше, чтобы понять получше эту тему.

3 апреля 2014 г.

Сохранение состояния Активности. Часть 1

Продолжаем перевод статьи с альма-матер. Начало статьи тут.

В начале надо сказать, что пользоваться эмулятором AVD для Android 2.3.3, крайне не рекомендуется, так как он крайне глюкавый, как оказалось. Выражалось это в том, что он ни как не отображал вызов метода onRestoreInstanceState, а так же не корректно отображал поведение приложения при повороте экрана. Поэтому рекомендую использовать Genymotion или же реальное устройство для тестирования приложения которое я приведу ниже.

А сейчас продолжение перевода.

Система вызывает метод onSaveInstanceState() перед тем как активность может быть уничтожена. Система передает в этот метод объект Bundle, в котором вы можете сохранить состояние параметров активности в виде пар “параметр”-“значение”, используя такие методы как putString() и putInt(). Затем, если система уничтожает процесс вашего приложения, а пользователь решает вернуться к вашей Актиновсти, то система восстанавливает Активность и передает ей объект Bundle в методах onCreate() и onRestoreInstanceState().Используя эти методы вы можете извлечь сохраненные данные из объекта Bundle и восстановить состояние Активности. Если же ни какой информации для восстановления нет, то объект Bundle вернет вам значение null (обычно такое бывает в случае когда активность создается в первый раз).

restore_instance

На рисунке показано два варианта когда Активность получает фокус и ее состояние сохраняется и восстанавливается или остается не тронутым. Если Активность уничтожается и затем воссоздается, то ее состояние восстанавливается из сохраненного состояния. Если же Активность была приостановлена и затем ее работа была возобновлена, то ее состояние остается нетронутым.

И еще раз приведу интересное замечание из предыдущей статьи.

Нет ни какой гарантии что onSaveInstanceState() будет вызвана перед тем как ваша Активность будет уничтожена, поскольку есть случаи в которых сохранение состояния не является необходимым (например, когдапользователь покидает вашу активность используя кнопку ОБРАТНО, то это означает, что пользователь сам прекратил работу с Активностью). Если система вызывает onSaveInstanceState(), то делает это до onStop() ивозможно перед onPause().

Однако, даже если вы не используете метод onSaveInstanceState(), некоторые данные состояния Активности восстанавливаются классом Активности по умолчанию поскольку к ним по умолчанию применяется метод onSaveInstanceState(). В частности метод onSaveInstanceState(), по умолчанию, сохраняется состояние каждого View в разметке (layout). Почти каждый виджет в Андроид использует этот метод для сохранения своего состояния, так чтобы любые видимые изменения в UI сохранялись и восстанавливались автоматически при воссоздании Активности. Например, виджет EditText сохраняет любой текст введенный в него пользователем, а виджет CheckBox сохраняет состояние был он отмечен или нет. Единственное что от вас требуется для этого, то это присвоить каждому виджету, состояние которого вы хотите сохранить, уникальный идентификатор ID (атрибут android:id). Если у виджета нет ID, то система не сможет сохранить его состояние.

Хотя метод onSaveInstanceState() и сохраняет, по умолчанию, состояние UI Активности, все же иногда может потребоваться его переопределить, чтобы сохранить дополнительную информацию. Для этого вы всегда должны вызывать суперкласс метода onSaveInstanceState() перед тем как сделаете, что либо еще. Так же необходимо будет переопределить и метод onRestoteInstanceState() вызвав его суперкласс и восстановив необходимую дополнительную информацию.

При необходимости, вы можете предотвратить чтобы представления (view) сохраняли свое состояние установив значение атрибута android:saveEnabled в false или же воспользовавшись методом setSaveEnabled(). Хотя обычно в этом нет необходимости, но все же у вас есть возможность сохранять состояние UI активности другим способом.

Примечание: Поскольку не гарантируется что метод onSaveInstanceState() будет вызван, вы должны использовать его только для сохранения временных данных состояния UI Активности и ни когда не использовать его для сохранения постоянных данных. Вместо него вы должны использовать метод onPause() для сохранения постоянных данных, если это необходимо, кода пользователь покидает Активность.

В следующей части будет немного практики на эту тему.