page.title=Операции page.tags=операция,намерение @jd:body

Содержание документа

  1. Создание операции
    1. Реализация пользовательского интерфейса
    2. Объявление операции в манифесте
  2. Запуск операции
    1. Запуск операции для получения результата
  3. Завершение операции
  4. Управление жизненным циклом операций
    1. Реализация обратных вызовов жизненного цикла
    2. Сохранение состояния операции
    3. Обработка изменений в конфигурации
    4. Согласование операций

Ключевые классы

  1. {@link android.app.Activity}

См. также:

  1. Задачи и стек переходов назад

{@link android.app.Activity} — это компонент приложения, который выдает экран, и с которым пользователи могут взаимодействовать для выполнения каких-либо действий, например набрать номер телефона, сделать фото, отправить письмо или просмотреть карту. Каждой операции присваивается окно для прорисовки соответствующего пользовательского интерфейса. Обычно окно отображается во весь экран, однако его размер может быть меньше, и оно может размещаться поверх других окон.

Как правило, приложение состоит из нескольких операций, которые слабо связаны друг с другом. Обычно одна из операций в приложении обозначается как «основная», предлагаемая пользователю при первом запуске приложения. В свою очередь, каждая операция может запустить другую операцию для выполнения различных действий. Каждый раз, когда запускается новая операция, предыдущая операция останавливается, однако система сохраняет ее в стеке («стек переходов назад»). При запуске новой операции она помещается в стек переходов назад и отображается для пользователя. Стек переходов назад работает по принципу «последним вошёл — первым вышел», поэтому после того как пользователь завершил текущую операцию и нажал кнопку Назад, текущая операция удаляется из стека (и уничтожается), и возобновляется предыдущая операция. (Подробные сведения о стеке переходов назад представлены в статье Задачи и стек переходов назад.)

Когда операция останавливается по причине запуска новой операции, для уведомления об изменении ее состояния используются методы обратного вызова жизненного цикла операции. Существует несколько таких методов, которые может принимать операция вследствие изменения своего состояния — создание операции, ее остановка, возобновление или уничтожение системой; также каждый обратный вызов представляет возможность выполнить определенное действие, подходящее для соответствующего изменения состояния. Например, в случае остановки операция должна освободить любые крупные объекты, например, подключение к сети или базе данных. При возобновлении операции вы можете повторно получить необходимые ресурсы и возобновить выполнение прерванных действий. Такие изменения состояния являются частью жизненного цикла операции.

Далее в этом документе рассматриваются основы создания и использования операций, включая полное описание жизненного цикла операции, чтобы вы могли лучше понять, как следует управлять переходами между различными состояниями операции.

Создание операции

Чтобы создать операцию, сначала необходимо создать подкласс класса {@link android.app.Activity} (или воспользоваться существующим его подклассом). В таком подклассе необходимо реализовать методы обратного вызова, которые вызывает система при переходе операции из одного состояния своего жизненного цикла в другое, например при создании, остановке, возобновлении или уничтожении операции. Вот два наиболее важных метода обратного вызова:

{@link android.app.Activity#onCreate onCreate()}
Этот метод необходимо обязательно реализовать, поскольку система вызывает его при создании вашей операции. В своей реализации вам необходимо инициализировать ключевые компоненты операции. Наиболее важно именно здесь вызвать {@link android.app.Activity#setContentView setContentView()} для определения макета пользовательского интерфейса операции.
{@link android.app.Activity#onPause onPause()}
Система вызывает этот метод в качестве первого признака выхода пользователя из операции (однако это не всегда означает, что операция будет уничтожена). Обычно именно здесь необходимо применять любые изменения, которые должны быть сохранены помимо текущего сеанса работы пользователя (поскольку пользователь может не вернуться назад).

Существуют также и некоторые другие методы обратного вызова жизненного цикла, которые необходимо использовать для того, чтобы обеспечить плавный переход между операциями, а также для обработки непредвиденных нарушений в работе операции, в результате которых она может быть остановлена или даже уничтожена. Более подробное описание всех методов обратного вызова жизненного цикла представлены в разделе, посвященном управлению жизненным циклом операций.

Реализация пользовательского интерфейса

Для реализации пользовательского интерфейса операции используется иерархия представлений —объектов, полученных из класса {@link android.view.View}. Каждое представление отвечает за определенную прямоугольную область окна операции и может реагировать на действия пользователей. Например, представлением может быть кнопка, нажатие на которую приводит к выполнению определенного действия.

В Android предусмотрен набор уже готовых представлений, которые можно использовать для создания дизайна макета и его организации. Виджеты — это представления с визуальными (и интерактивными) элементами, например, кнопками, текстовыми полями, чекбоксами или просто изображениями. Макеты — это представления, полученные из класса {@link android.view.ViewGroup}, обеспечивающие уникальную модель компоновки для своих дочерних представлений, таких как линейный макет, сетка или относительный макет. Также можно создать подкласс для классов {@link android.view.View} и {@link android.view.ViewGroup} (или воспользоваться существующими подклассами), чтобы создать собственные виджеты и макеты, и затем применить их к макету своей операции.

Чаще всего для задания макета с помощью представлений используется XML-файл макета, сохраненный в ресурсах приложения. Таким образом вы можете хранить дизайн пользовательского интерфейса отдельно от исходного кода, который служит для задания поведения операции. Чтобы задать макет в качестве пользовательского интерфейса операции, можно использовать метод {@link android.app.Activity#setContentView(int) setContentView()}, передав в него идентификатор ресурса для макета. Однако вы также можете создать новые {@link android.view.View} в коде вашей операции и создать иерархию представлений. Для этого вставьте {@link android.view.View} в {@link android.view.ViewGroup}, а затем используйте этот макет, передав корневой объект {@link android.view.ViewGroup} в метод {@link android.app.Activity#setContentView(View) setContentView()}.

Подробные сведения о создании пользовательского интерфейса см. в статье Пользовательский интерфейс.

Объявление операции в манифесте

Чтобы операция стала доступна системе, ее необходимо объявить в файле манифеста. Для этого откройте файл манифеста и добавьте элемент {@code <activity>} в качестве дочернего для элемента {@code <application>}. Например:

<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

Существует несколько других атрибутов, которые можно включить в этот элемент, чтобы определить такие свойства, как метка операции, значок операции или тема оформления для пользовательского интерфейса операции. Единственным обязательным атрибутом является {@code android:name} — он определяет имя класса операции. После публикации вашего приложения вам не следует переименовывать его, поскольку это может нарушить некоторые функциональные возможности приложения, например, ярлыки приложения (ознакомьтесь с публикацией Вещи , которые нельзя менять в блоге разработчиков).

Дополнительные сведения об объявлении операции в манифесте см. в справке по элементу {@code <activity>}.

Использование фильтров намерений

Элемент {@code <activity>} также может задавать различные фильтры намерений — с помощью элемента {@code <intent-filter>} — для объявления того, как другие компоненты приложения могут активировать операцию.

При создании нового приложения с помощью инструментов Android SDK в заготовке операции, создаваемой автоматически, имеется фильтр намерений, который объявляет операцию. Эта операция реагирует на выполнение «основного» действия, и ее следует поместить в категорию переходсредства запуска. Фильтр намерений выглядит следующим образом.

<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Элемент {@code <action>} указывает, что это «основная» точка входа в приложение. Элемент {@code <category>}указывает, что эту операцию следует указать в средстве запуска приложений системы (чтобы пользователи могли запускать эту операцию).

Если приложение планируется создать самодостаточным и запретить другим приложениям активировать его операции, то других фильтров намерений создавать не нужно. В этом случае только в одной операции должно иметься «основное» действие, и ее следует поместить в категорию средства запуска, как в примере выше. В операциях, которые не должны быть доступны для других приложений, не следует включать фильтры намерений. Вы можете самостоятельно запустить такие операции с помощью явных намерений (как описывается в следующем разделе).

Однако, если вам необходимо, чтобы операция реагировала на неявные намерения, получаемые от других приложений (а также из вашего приложения), для операции необходимо определить дополнительные фильтры намерений. Для каждого типа намерения, на который необходимо реагировать, необходимо указать объект {@code <intent-filter>}, включающий элемент {@code <action>} и необязательный элемент {@code <category>} или {@code <data>} (или оба этих элемента). Эти элементы определяют тип намерения, на который может реагировать ваша операция.

Дополнительные сведения о том, как операции могут реагировать на намерения, приведены в статье Намерения и фильтры намерений.

Запуск операции

Для запуска другой операции достаточно вызвать метод {@link android.app.Activity#startActivity startActivity()}, передав в него объект {@link android.content.Intent}, который описывает запускаемую операцию. В намерении указывается либо точная операция для запуска, либо описывается тип операции, которую вы хотите выполнить (после чего система выбирает для вас подходящую операцию, которая может даже находиться в другом приложении). Намерение также может содержать небольшой объем данных, которые будут использоваться запущенной операцией.

При работе с собственным приложением зачастую требуется лишь запустить нужную операцию. Для этого необходимо создать намерение, которое явно определяет требуемую операцию с помощью имени класса. Ниже представлен пример запуска одной операцией другой операции с именем {@code SignInActivity}.

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

Однако в вашем приложении также может потребоваться выполнить некоторое действие, например, отправить письмо, текстовое сообщение или обновить статус, используя данные из вашей операции. В этом случае в вашем приложении могут отсутствовать такие действия, поэтому вы можете воспользоваться операциями из других приложений, имеющихся на устройстве, которые могут выполнять требуемые действия. Как раз в этом случае намерения особенно полезны — можно создать намерение, которое описывает необходимое действие, после чего система запускает его из другого приложения. При наличии нескольких операций, которые могут обработать намерение, пользователь может выбирать, какое из них следует использовать. Например, если пользователю требуется предоставить возможность отправить электронное письмо, можно создать следующее намерение:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

Дополнительный компонент {@link android.content.Intent#EXTRA_EMAIL}, добавленный в намерение, представляет собой строковый массив адресов электронной почты для отправки письма. Когда почтовая программа реагирует на это намерение, она считывает дополнительно добавленный строковый массив и помещает имеющиеся в нем адреса в поле получателя в окне создания письма. При этом запускается операция почтовой программы, а после того, как пользователь завершит требуемые действия, возобновляется ваша операция.

Запуск операции для получения результата

В некоторых случаях после запуска операции может потребоваться получить результат. Для этого вызовите метод {@link android.app.Activity#startActivityForResult startActivityForResult()} (вместо {@link android.app.Activity#startActivity startActivity()}). Чтобы получить результат после выполнения последующей операции, реализуйте метод обратного вызова {@link android.app.Activity#onActivityResult onActivityResult()}. По завершении последующей операции она возвращает результат в объекте {@link android.content.Intent} в вызванный метод {@link android.app.Activity#onActivityResult onActivityResult()}.

К примеру, пользователю потребуется выбрать один из контактов, чтобы ваша операция могла выполнить некоторые действия с информацией об этом контакте. Ниже представлен пример создания такого намерения и обработки результата.

private void pickContact() {
    // Create an intent to "pick" a contact, as defined by the content provider URI
    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    startActivityForResult(intent, PICK_CONTACT_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
        // Perform a query to the contact's content provider for the contact's name
        Cursor cursor = getContentResolver().query(data.getData(),
        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
        if (cursor.moveToFirst()) { // True if the cursor is not empty
            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
            String name = cursor.getString(columnIndex);
            // Do something with the selected contact's name...
        }
    }
}

В этом примере демонстрируется базовая логика, которой следует руководствоваться при использовании метода {@link android.app.Activity#onActivityResult onActivityResult()} для обработки результата выполнения операции. Первое условие проверяет, успешен ли запрос, и если он успешен, то результат для {@code resultCode} будет {@link android.app.Activity#RESULT_OK}; также проверяется, известен ли запрос, для которого получен этот результат, и в этом случае {@code requestCode} соответствует второму параметру, отправленному в метод {@link android.app.Activity#startActivityForResult startActivityForResult()}. Здесь код обрабатывает результат выполнения операции путем запроса данных, возвращенных в {@link android.content.Intent} (параметр {@code data}).

При этом {@link android.content.ContentResolver} выполняет запрос к поставщику контента, который возвращает объект {@link android.database.Cursor}, обеспечивающий считывание запрошенных данных. Дополнительные сведения представлены в статье Поставщики контента.

Дополнительные сведения об использовании намерений см. в статье Намерения и фильтры намерений.

Завершение операции

Для завершения операции достаточно вызвать ее метод {@link android.app.Activity#finish finish()}. Также для завершения отдельной операции, запущенной ранее, можно вызвать метод {@link android.app.Activity#finishActivity finishActivity()}.

Примечание. В большинстве случаев вам не следует явно завершать операцию с помощью этих методов. Как указано в следующем разделе, посвященном управлению жизненным циклом операции, система Android выполняет такое управление за вас, поэтому вам не нужно завершать ваши собственные операции. Вызов этих методов может отрицательно сказаться на ожидаемом поведении приложения. Их следует использовать исключительно тогда, когда вы абсолютно не хотите, чтобы пользователь возвращался к этому экземпляру операции.

Управление жизненным циклом операций

Управление жизненным циклом операций путем реализации методов обратного вызова имеет важное значение при разработке надежных и гибких приложений. На жизненный цикл операции напрямую влияют его связи с другими операциями, его задачами и стеком переходов назад.

Существует всего три состояния операции:

Возобновлена
Операция выполняется на переднем плане экрана и отображается для пользователя. (Это состояние также иногда называется «Выполняется».)
Приостановлена
На переднем фоне выполняется другая операция, которая отображается для пользователя, однако эта операция по-прежнему не скрыта. То есть поверх текущей операции отображается другая операция, частично прозрачная или не занимающая полностью весь экран. Приостановленная операция полностью активна (объект {@link android.app.Activity} по-прежнему находится в памяти, в нем сохраняются все сведения о состоянии и информация об элементах, и он также остается связанным с диспетчером окон), однако в случае острой нехватки памяти система может завершить ее.
Остановлена
Операция полностью перекрывается другой операцией (теперь она выполняется в фоновом режиме). Остановленная операция по-прежнему активна (объект {@link android.app.Activity} по-прежнему находится в памяти, в нем сохраняются все сведения о состоянии и информация об элементах, но объект больше не связан с диспетчером окон). Однако операция больше не видна пользователю, и в случае нехватки памяти система может завершить ее.

Если операция приостановлена или полностью остановлена, система может очистить ее из памяти путем завершения самой операции (с помощью метода {@link android.app.Activity#finish finish()}) или просто завершить ее процесс. В случае повторного открытия операции (после ее завершения) ее потребуется создать полностью.

Реализация обратных вызовов жизненного цикла

При переходе операции из одного вышеописанного состояния в другое, уведомления об этом реализуются через различные методы обратного вызова. Все методы обратного вызова представляют собой привязки, которые можно переопределить для выполнения подходящего действия при изменении состояния операции. Указанная ниже базовая операция включает каждый из основных методов жизненного цикла.

public class ExampleActivity extends Activity {
    @Override
    public void {@link android.app.Activity#onCreate onCreate}(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The activity is being created.
    }
    @Override
    protected void {@link android.app.Activity#onStart onStart()} {
        super.onStart();
        // The activity is about to become visible.
    }
    @Override
    protected void {@link android.app.Activity#onResume onResume()} {
        super.onResume();
        // The activity has become visible (it is now "resumed").
    }
    @Override
    protected void {@link android.app.Activity#onPause onPause()} {
        super.onPause();
        // Another activity is taking focus (this activity is about to be "paused").
    }
    @Override
    protected void {@link android.app.Activity#onStop onStop()} {
        super.onStop();
        // The activity is no longer visible (it is now "stopped")
    }
    @Override
    protected void {@link android.app.Activity#onDestroy onDestroy()} {
        super.onDestroy();
        // The activity is about to be destroyed.
    }
}

Примечание. При реализации этих методов жизненного цикла всегда вызывайте реализацию суперкласса, прежде чем выполнять какие-либо действия, как показано в примерах выше.

Вместе все эти методы определяют весь жизненный цикл операции. С помощью реализации этих методов можно отслеживать три вложенных цикла в жизненном цикле операции:

На рисунке 1 иллюстрируются проходы и пути, которые операция может пройти между состояниями. Прямоугольниками обозначены методы обратного вызова, которые можно реализовать для выполнения действий между переходами операции из одного состояния в другое.

Рисунок 1. Жизненный цикл операции.

Эти же методы жизненного цикла перечислены в таблице 1, в которой подробно описан каждый метод обратного вызова и указано его место в жизненном цикле операции в целом, включая сведения о том, может ли система завершить операцию по завершении метода обратного вызова.

Таблица 1. Сводные сведения о методах обратного вызова жизненного цикла операции.

Метод Описание Завершаемый? Следующий
{@link android.app.Activity#onCreate onCreate()} Вызывается при первом создании операции. Здесь необходимо настроить все обычные статические элементы — создать представления, привязать данные и т. д. Этот метод передает объект Bundle, содержащий предыдущее состояние операции (если такое состояние было зафиксировано ранее; см. раздел Сохранение состояния операции).

За ним всегда следует метод {@code onStart()}.

Нет {@code onStart()}
     {@link android.app.Activity#onRestart onRestart()} Вызывается после остановки операции непосредственно перед ее повторным запуском.

За ним всегда следует метод {@code onStart()}.

Нет {@code onStart()}
{@link android.app.Activity#onStart onStart()} Вызывается непосредственно перед тем, как операция становится видимой для пользователя.

За ним следует метод {@code onResume()}, если операция переходит на передний план, или метод {@code onStop()}, если она становится скрытой.

Нет {@code onResume()}
или
{@code onStop()}
     {@link android.app.Activity#onResume onResume()} Вызывается непосредственно перед тем, как операция начинает взаимодействие с пользователем. На этом этапе операция находится в самом верху стека операций, и в нее поступают данные, вводимые пользователем.

За ним всегда следует метод {@code onPause()}.

Нет {@code onPause()}
{@link android.app.Activity#onPause onPause()} Вызывается, когда система собирается возобновить другую операцию. Этот метод обычно используется для записи несохраненных изменений в постоянное место хранения данных, остановки анимаций и других элементов, которые могут использовать ресурсы ЦП и т. д. Здесь крайне важна оперативность, поскольку следующая операция не будет возобновлена до тех пор, пока она не будет возвращена на передний план.

За ним следует либо метод {@code onResume()}, если операция возвращается на передний план, либо метод {@code onStop()}, если операция становится скрытой для пользователя.

Да {@code onResume()}
или
{@code onStop()}
{@link android.app.Activity#onStop onStop()} Вызывается в случае, когда операция больше не отображается для пользователя. Это может произойти по причине того, что операция уничтожена, или ввиду возобновления поверх нее другой операции (существующей или новой).

За ним следует либо метод {@code onRestart()}, если операция возобновляет взаимодействие с пользователем, либо метод {@code onDestroy()}, если операция переходит в фоновый режим.

Да {@code onRestart()}
или
{@code onDestroy()}
{@link android.app.Activity#onDestroy onDestroy()} Вызывается перед тем, как операция будет уничтожена. Это финальный вызов, который получает операция. Его можно вызвать либо по причине завершения операции (вызов метода {@link android.app.Activity#finish finish()}), либо ввиду временного уничтожения системой этого экземпляра операции с целью освободить место. Чтобы различить эти два сценария, используется метод {@link android.app.Activity#isFinishing isFinishing()}. Да Ничего

В столбце «Завершаемый?» указывается, может ли система в любое время завершить процесс, содержащий операцию, после возвращения метода без выполнения другой строки кода операции. Для трех методов в этом столбце указано «Да»: ({@link android.app.Activity#onPause onPause()}, {@link android.app.Activity#onStop onStop()} и {@link android.app.Activity#onDestroy onDestroy()}). Поскольку метод {@link android.app.Activity#onPause onPause()} является первым из этих трех после создания операции, метод {@link android.app.Activity#onPause onPause()} является последним, который гарантированно будет вызван перед тем, как процесс можно будет завершить; если системе потребуется срочно восстановить память в случае аварийной ситуации, то методы {@link android.app.Activity#onStop onStop()} и {@link android.app.Activity#onDestroy onDestroy()} вызвать не удастся. Поэтому следует воспользоваться {@link android.app.Activity#onPause onPause()}, чтобы записать критически важные данные (такие как правки пользователя) в хранилище постоянных данных. Однако следует внимательно подходить к выбору информации, которую необходимо сохранить во время выполнения метода {@link android.app.Activity#onPause onPause()}, поскольку любая блокировка процедур в этом методе может вызвать блокирование перехода к следующей операции и тормозить работу пользователя.

Методы, для которых в столбце Завершаемый? указано «Нет», защищают процесс, содержащий операцию , от завершения сразу с момента их вызова. Поэтому завершить операцию можно в период между возвратом {@link android.app.Activity#onPause onPause()} и вызовом {@link android.app.Activity#onResume onResume()}. Его снова не удастся завершить, пока снова не будет вызван и возвращен {@link android.app.Activity#onPause onPause()}.

Примечание. Операцию, которую технически невозможно завершить в соответствии с определением в таблице 1, по-прежнему может завершить система, однако это может произойти только в чрезвычайных ситуациях, когда нет другой возможности. Случаи, когда возможно завершение операции, более подробно рассматриваются в статьеПроцессы и потоки.

Сохранение состояния операции

В обзорных сведениях об управлении жизненным циклом операции кратко упоминается, что в случае приостановки или полной остановки операции ее состояние сохраняется. Это действительно так, поскольку объект {@link android.app.Activity} при этом по-прежнему находится в памяти , и вся информация о ее элементах и текущем состоянии по-прежнему активна. Поэтому любые вносимые пользователем в операции изменения сохраняются, и когда операция возвращается на передний план (когда она «возобновляется»), эти изменения остаются в этом объекте.

Однако когда система уничтожает операцию в целях восстановления памяти, объект {@link android.app.Activity} уничтожается, в результате чего системе не удается просто восстановить состояние операции для взаимодействия с ней. Вместо этого системе необходимо повторно создать объект {@link android.app.Activity}, если пользователь возвращается к нему. Но пользователю неизвестно, что система уже уничтожила операцию и создала ее повторно, поэтому, возможно, он ожидает, что операция осталась прежней. В этой ситуации можно обеспечить сохранение важной информации о состоянии операции путем реализации дополнительного метода обратного вызова, который позволяет сохранить информацию о вашей операции: {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}.

Прежде чем сделать операцию доступной для уничтожения, система вызывает метод {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}. Система передает в этот метод объект {@link android.os.Bundle}, в котором можно сохранить информацию о состоянии операции в виде пар «имя-значение», используя для этого такие методы, как {@link android.os.Bundle#putString putString()} и {@link android.os.Bundle#putInt putInt()}. Затем, если система завершает процесс вашего приложения и пользователь возвращается к вашей операции, система повторно создает операцию и передает объект {@link android.os.Bundle} в оба метода: {@link android.app.Activity#onCreate onCreate()} и {@link android.app.Activity#onRestoreInstanceState onRestoreInstanceState()}. С помощью любого из этих методов можно извлечь из объекта {@link android.os.Bundle} сохраненную информацию о состоянии операции и восстановить ее. Если такая информация отсутствует, то объект {@link android.os.Bundle} передается с нулевым значением (это происходит в случае, когда операция создается в первый раз).

Рисунок 2. Два способа возврата операции к отображению для пользователя в неизмененном состоянии: уничтожение операции с последующим ее повторным созданием, когда операция должна восстановить свое ранее сохраненное состояние, или остановка операции и ее последующее восстановление в неизмененном состоянии.

Примечание. Нет никаких гарантий, что метод {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} будет вызван до того, как ваша операция будет уничтожена, поскольку существуют случаи, когда нет необходимости сохранять состояние (например, когда пользователь покидает вашу операцию нажатием кнопки Назад, явным образом закрывая ее). Если система вызывает метод {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}, она делает это до вызова метода {@link android.app.Activity#onStop onStop()} и, возможно, перед вызовом метода {@link android.app.Activity#onPause onPause()}.

Однако, даже если вы ничего не предпринимаете и не реализуете метод {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}, часть состояния операции восстанавливается реализацией по умолчанию метода {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} класса {@link android.app.Activity}. В частности, реализация по умолчанию вызывает соответствующий метод {@link android.view.View#onSaveInstanceState onSaveInstanceState()} для каждого объекта {@link android.view.View} в макете, благодаря чему каждое представление может предоставлять ту информацию о себе, которую следует сохранить. Почти каждый виджет в платформе Android реализует этот метод необходимым для себя способом так, что любые видимые изменения в пользовательском интерфейсе автоматически сохраняются и восстанавливаются при повторном создании операции. Например, виджет {@link android.widget.EditText} сохраняет любой текст, введенный пользователем, а виджет {@link android.widget.CheckBox} сохраняет информацию о том, был ли установлен флажок. От вас требуется лишь указать уникальный идентификатор (с атрибутом {@code android:id}) для каждого виджета, состояние которого необходимо сохранить. Если виджету не присвоен идентификатор, то системе не удастся сохранить его состояние.

Несмотря на то что реализация метода {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} по умолчанию позволяет сохранить полезную информацию о пользовательском интерфейсе вашей операции, вам по-прежнему может потребоваться переопределить ее для сохранения дополнительной информации. Например, может потребоваться сохранить значения элементов, которые изменялись в течение жизненного цикла операции (которые могут коррелировать со значениями, восстановленными в пользовательском интерфейсе, однако элементы, содержащие эти значения пользовательского интерфейса, по умолчанию не были восстановлены).

Поскольку реализация метода {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} по умолчанию позволяет сохранить состояние пользовательского интерфейса, в случае , если вы переопределите метод с целью сохранить дополнительную информацию о состоянии, перед выполнением каких-либо действий вы всегда можете вызвать реализацию суперкласса для метода {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()}. Точно так же реализацию суперкласса {@link android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} следует вызывать в случае ее переопределения, чтобы реализация по умолчанию могла сохранить состояния представлений.

Примечание. Поскольку вызов метода {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} не гарантируется, вам следует использовать его только для записи переходного состояния операции (состояние пользовательского интерфейса) — никогда не используйте его для хранения постоянных данных. Вместо этого используйте метод {@link android.app.Activity#onPause onPause()} для сохранения постоянных данных (например, тех, которые следует сохранить в базу данных), когда пользователь покидает операцию.

Отличный способ проверить возможность вашего приложения восстанавливать свое состояние — это просто повернуть устройство для изменения ориентации экрана. При изменении ориентации экрана система уничтожает и повторно создает операцию, чтобы применить альтернативные ресурсы, которые могут быть доступны для новой конфигурации экрана. Только по одной этой причине крайне важно, чтобы ваша операция могла полностью восстанавливать свое состояние при ее повторном создании, поскольку пользователи постоянно работают с приложениями в разных ориентациях экрана.

Обработка изменений в конфигурации

Некоторые конфигурации устройств могут изменяться в режиме выполнения (например, ориентация экрана, доступность клавиатуры и язык). В таких случаях Android повторно создает выполняющуюся операцию (система сначала вызывает метод {@link android.app.Activity#onDestroy}, а затем сразу же вызывает метод {@link android.app.Activity#onCreate onCreate()}). Такое поведение позволяет приложению учитывать новые конфигурации путем автоматической перезагрузки в приложение альтернативных ресурсов, которые вы предоставили (например, различные макеты для разных ориентаций и экранов разных размеров).

Если операция разработана должным образом и должным образом поддерживает перезапуск после изменения ориентации экрана и восстановление своего состояния, как описано выше, ваше приложение можно считать более устойчивым к другим непредвиденным событиям в жизненном цикле операции.

Лучший способ обработки такого перезапуска — сохранить и восстановить состояние операции с помощью методов {@link android.app.Activity#onSaveInstanceState onSaveInstanceState()} и {@link android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} (или {@link android.app.Activity#onCreate onCreate()}), как описано в предыдущем разделе.

Дополнительные сведения об изменениях конфигурации, происходящих в режиме выполнения, и о способах их обработки представлены в руководствеОбработка изменений в режиме выполнения.

Согласование операций

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

Порядок обратных вызовов жизненного цикла четко определен, в частности, когда в одном и том же процессе находятся две операции , и одна из них запускает другую. Ниже представлен порядок выполнения действий в случае, когда операция А запускает операцию Б.

  1. Выполняется метод {@link android.app.Activity#onPause onPause()} операции А.
  2. Последовательно выполняются методы {@link android.app.Activity#onCreate onCreate()}, {@link android.app.Activity#onStart onStart()} и {@link android.app.Activity#onResume onResume()} операции Б. (Теперь для пользователя отображается операция Б.)
  3. Затем, если операция A больше не отображается на экране, выполняется ее метод {@link android.app.Activity#onStop onStop()}.

Такая предсказуемая последовательность выполнения обратных вызовов жизненного цикла позволяет управлять переходом информации из одной операции в другую. Например, если после остановки первой операции требуется выполнить запись в базу данных, чтобы следующая операция могла считать их, то запись в базу данных следует выполнить во время выполнения метода {@link android.app.Activity#onPause onPause()}, а не во время выполнения метода {@link android.app.Activity#onStop onStop()}.