12 марта 2014 г.

Задачи и обратный стек (Tasks and back stack). Часть 1

Это следующий, более глубокий этап понимания жизненных циклов Активностей.

На эту тему уже был перевод статьи с альма-матер

http://habrahabr.ru/post/186434/

но он очень вольный (хотя у меня такие же) и кроме того там есть парочка серьезных ошибок, но при обращении к оригинальной статье все становится на свои места. Так или иначе перевод полезный и его стоит почитать для общего понимания темы. Я тут буду излагать свой. Местами они будут повторяться, но я надеюсь что сделаю более полный перевод. Кроме того я приведу приложения демонстрирующие все эти концепции, так чтобы можно было на практике увидеть, что к чему.

Кроме того в создании этой заметки помог так же материал вот от сюда

http://startandroid.ru/ru/uroki/vse-uroki-spiskom/190-urok-116-povedenie-activity-v-task-intent-flagi-launchmode-affinity

http://startandroid.ru/ru/uroki/vse-uroki-spiskom/62-urok-25-task-chto-eto-takoe-i-kak-formiruetsja.html

http://habrahabr.ru/post/201214/

http://habrahabr.ru/post/201886/

И так! Поехали!

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

Активность одного приложения может запустить Активность из другого приложения. Например, ваше приложение хочет отправить сообщение по электронной почте, вы можете это сделать с помощью намерения (intent) с действием SEND, в которое как данные включаете адрес назначения и текст письма, а Активность из другого приложения которая заявила что может поддерживать подобные намерения intent с действием SEND, может принять ваши данные и открыть свою Активность для отправки сообщения. Когда сообщение будет отослано, ваша Активность снова появится на экране и будет казаться, как будто Активность отсылки электронной почты является частью вашего приложения. Даже если Активности принадлежат разным приложениям, Андроид поддерживает видимость для пользователя как будто это одно приложение, храня обе Активности в одной задаче.

Задача – это набор Активностей находящихся в одном стеке, которые пользователь запускает для выполнения какой либо своей задачи. Активности находятся в стеке (обратном стеке) в том порядке в каком их вызывал пользователь.

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

Когда текущая Активность запускает другую, новая Активность помещается на вершину стека, а предыдущая занимает место под ней и переходит в остановленное состояние. Когда активность останавливается, система сохраняет состояние ее интерфейса. Когда пользователь нажимает кнопку ОБРАТНО, текущая Активность изымается из вершины стека и уничтожается методом onDestroy, и фокус получает Активность, которая находилась под ней. Она помещается на вершину стека и ее состояние восстанавливается методом onResume. Активности в стеке ни когда не реорганизуются, то есть не меняют своего положения в стеке. Они только помещаются на вершину стека, когда пользователь запускает Активность или изымаются с вершины стека, когда пользователь нажимает кнопку ОБРАТНО на текущей Активности. Стек организован по принципу «last in, first out» — т.е. последний вошел, первый вышел. На диаграмме ниже это хорошо показано.

diagram_backstack

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

Кроме того, как раз это поведение детально и было рассмотрено в моей предыдущей статье.

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

Задача продолжает существовать даже когда находится в фоновом режиме. Задача переходит в фоновый режим, когда пользователь запускает новую задачу или когда переходит на домашний экран нажав кнопку HOME. Все Активности в фоновой задаче находятся в остановленном состоянии, обратный стек задачи сохраняет свое состояние, задача просто потеряла фокус, поскольку фокус получила другая задача. Это показано на диаграмме ниже:

diagram_multitasking

Тут две задачи. Задача B взаимодействует с пользователем и находится в фокусе (на переднем плане). В то время как задача A находится в фоне ожидая возобновления работы. Каждая задача имеет свой обратный стек Активностей. Пользователь может переключаться между задачами. Тогда одна из них теряет фокус и переходит на задний план, а другая получает фокус и переходит на передний план. Это пример многозадачности Андроид.

 

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

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

Итак, подведем итог поведения Активности по умолчанию:

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

Пример поведения Активностей описанных в этой части, можно посмотреть в моей предыдущей статье.

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

Комментариев нет:

Отправить комментарий