- PVSM.RU - https://www.pvsm.ru -
Привет. Из названия темы вы могли заметить, что речь пойдет о том, как устроены Tasks и Back Stack в Android. Эта статья будет являться свободным переводом офф. исочника [1]. Тема больше ориентирована на новичков, но я думаю, что и опытный разработчик сможет узнать что-то новое, т.к. тема специфична и не часто приходится кастомизировать поведение наших Activity.
И так. Каждое Android приложение, как минимум, состоит из фундоментальных объектов системы — Activity. Activity — это отдельный экран который имеет свою отдельную логику и UI. Количество Activity в приложении бывает разное, от одного до много. При переходах между различными Activity пользователь всегда может вернуться на предыдущую, закрытую Activity при нажатии кнопки back на устройстве. Подобная логика реализована с помощью стека (Activity Stack). Его организация «last in, first out» — т.е. последний вошел, первый вышел. При открытии новой Activity она становится вершиной, а придыдущая уходит в режим stop. Стек не может перемешиваться, он имеет возможность добавления на вершину новой Activity и удаление верхней текущей. Одна и таже Activity может находится в стеке, сколько угодно раз.
Task — это набор Activity. Каждый таск содержит свой стек. В стандартной ситуации, каждое приложение имеет свой таск и свой стек. При сворачивании приложения, таск уходит в background, но не умирает. Он хранит весь свой стек и при очередном открытии приложения через менеджер или через launcher, существующий таск восстановится и продолжит свою работу.

Если продолжать нажимать кнопку back, то стек будет удалять Activity до того, пока не останется главная корневая. Если же на ней пользователь нажмет back, приложение закроется и таск умрет. Кстати, я говорил о том, что когда мы сворачиваем наше приложение и запускам например новое, то наш таск просто уходит в background и будет ждать момента, пока мы его вызовем. На самом деле есть одно «но». Если мы будем иметь много задач в background или же просто сильно нагружать свое устройство, не мала вероятность того, что таск умрет из за нехватки системных ресурсов. Это не война конечно, но то что мы потеряем все наши текущие данные и наш стек очистится — это точно. Кстати для избежания потери данных в таком случаи, вам стоит почитать про SavingActivityState [2].
Все то что мы описали выше — это стандартное поведение для приложения Android. В большинстве случаев так все и должно быть. Но если вы все же желаете что-то поменять, возможности для этого есть. Они будут описаны дальше, а пока маленький итог того, что мы уже обсудили.
Существует два пути для изменения стандартной организации тасков. Мы можем устанавливать специальные аттрибуты в манифесте для каждой активити. Также мы можем устанавливать специальные флаги для Intent, который запускает новую Activity с помощью startActivity(). Заметьте, что иногда аттрибуты в манифесте и флаги в Intent могут противоречить друг другу. В этом случаи флаги Intent будут более приоритетны.
Для каждой Activity в манифесте можно указать аттрибут launchMode. Он имеет несколько значений:
На самом деле не важно, в каком таске открыта новая Activity. При нажатии кнопки back мы все равно вернемся на предыдущий таск и предыдущие Activity. Единственный момент, который нужно учитывать — это параметр singleTask. Если при открытии такой Activity мы достанем ее из другого background таска, то мы полностью переключаемся на него и на его стек. на картинке ниже это продемонстрировано.

Как и говорил, мы можем устанавливать специальный флаги для Intent, который запускает новую Activity. Флаги более приоритетны, чем launchMode. Существует несколько флагов:
Стандартно все Activity нашего приложения работают в одном таске. По желанию мы можем изменять такое поведение и указывать, чтобы в одном приложении Activity работали в разных тасках, или Activity разных приложений работали в одном. Для этого мы можем в манифесте для каждой Activity указывать название таска параметром taskAffinity. Это строковое значение, которое не должно совпадать с названием package, т.к. стандартный таск приложения называется именно как наш пакет. В общем случаи данный параметр указывает, что Activity будет гарантированно открываться в своём отдельном таске. Данный параметр акутален, если мы указываем флаг FLAG_ACTIVITY_NEW_TASK или устанавливаем для Activity аттрибут allowTaskReparenting=«true». Этот аттрибут указывает, что Activity может перемещатсья между тасками, который её запустил и таском, который указан в taskAffinity, если один из них становится активным.
Если таск долгое время находится в background, то система сама чистит его стек, оставляя только корневую Activity. Данное поведение обусловлено тем, что пользователь может забыть, что он делал в приложении до этого и скорее всего защел в него снова уже с другой целью. Данная логика также может быть изменена с помощью нескольких аттрибутов в манифесте.
Это всё для данного топика. Статья не импровизирована, а по сути является вольным переводом оффициальной документации [1]. Рекомендую собрать легкий пример и поэксперементировать с флагами и аттрибутами. Некоторые моменты, лично для меня были, неожиданно интересными. любые ошибки и недоработки учту в лс. Спасибо.
Автор: deM1d
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android/38564
Ссылки в тексте:
[1] офф. исочника: http://developer.android.com/guide/components/tasks-and-back-stack.html
[2] SavingActivityState: http://developer.android.com/guide/components/activities.html#SavingActivityState
[3] Источник: http://habrahabr.ru/post/186434/
Нажмите здесь для печати.