Ответ 1
Я посмотрел исходный код для ActivityManager
. Флаг Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
действительно выполняет некоторую магию, которая не выполняет Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
: она запускает задачу reparenting.
Здесь пример (хотя и хромой):
В приложении А мы имеем корневую активность RootA
, и у нас есть другая Activity ReparentableA
:
<application
android:label="@string/app_name">
<activity android:name=".RootA">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ReparentableA"
android:allowTaskReparenting="true"/>
</application>
Приложение A имеет имя пакета "com.app.a", поэтому по умолчанию taskAffinity
его компонентов "com.app.a".
В приложении B мы имеем корневую активность RootB
:
<application
android:label="@string/app_name">
<activity android:name="RootB">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
Приложение B имеет имя пакета "com.app.b", поэтому по умолчанию taskAffinity
его компонентов "com.app.b".
Теперь мы запускаем приложение B с экрана HOME. Это запустит новую задачу и создаст новый экземпляр Activity RootB
в качестве основной активности в этой задаче. Активность RootB
теперь запускает Activity ReparentableA
стандартным образом без каких-либо специальных флагов. Создается экземпляр ReparentableA
и помещается поверх RootB
в текущую задачу.
Нажмите HOME.
Теперь мы запускаем приложение А с экрана HOME. Это запустит новую задачу и создаст новый экземпляр Activity RootA
в качестве корневой активности в этой задаче. ПРИМЕЧАНИЕ. Когда Android запускает "Launcher" Intent, он автоматически устанавливает флаги Intent.FLAG_ACTIVITY_NEW_TASK
и Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
. Из-за этого запуск RootA
теперь вызывает повторное рассмотрение задачи. Android ищет, есть ли какие-либо действия в каких-либо других задачах, которые имеют сродство к этой новой задаче (и являются reparentable). Он находит ReparentableA
(с той же близостью задачи, что и RootA
) в задаче приложения B, и переводит его в новую задачу App A. При запуске приложения А мы не видим RootA
, на самом деле видим ReparentableA
, поскольку он перемещается в начало новой задачи.
Если мы вернемся в приложение B, мы увидим, что ReparentableA
ушел из стека задач, и эта задача теперь состоит только из одного действия: RootB
.
Заметки об использовании Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
Важно помнить об использовании этих флагов для "reset задачи" в том, что работает только в том случае, если в корне задачи уже есть экземпляр целевого Activity. Если ваша корневая активность когда-либо заканчивается, вы не можете очистить свою задачу, запустив корневую активность с помощью Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
. Android просто создаст новый экземпляр целевого (корневого) Activity и поместит его поверх существующих действий в задачу, что, вероятно, совсем не так, как вы хотите.
Разница между Intent.FLAG_ACTIVITY_CLEAR_TASK
и Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
:
Как отмечено выше, использование CLEAR_TOP | SINGLE_TOP
работает только в том случае, если в задаче уже есть экземпляр целевого Activity. CLEAR_TASK
, однако, удаляет все действия из задачи, независимо от того, был ли экземпляр целевого Activity в задаче. Кроме того, использование CLEAR_TASK
гарантирует, что целевая активность станет корневой операцией задачи, без необходимости знать, какая активность была корневой активностью перед очисткой задачи.
Разница между Intent.FLAG_ACTIVITY_CLEAR_TASK
и Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
:
Как указано выше, использование CLEAR_TASK
будет всегда удалять все действия из задачи и запускать новый экземпляр целевой активности. Напротив, RESET_TASK_IF_NEEDED
выполняет только reset задачу в определенных ситуациях (часть "IF_NEEDED" ). Задача - "reset" , если Android:
- Создание новой задачи (в этом случае функциональность "reset" включает объяснение задачи, описанную выше) или
- Если Android выводит фоновую задачу на передний план (в этом случае задача удаляется только из всех действий, запущенных с помощью
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
и любых действий, которые находятся поверх этих действий). ПРИМЕЧАНИЕ. В этом случае корневая активность никогда не очищается.
ВАЖНОЕ ПРИМЕЧАНИЕ:. Когда вы тестируете, обратите внимание, что существует разница в том, как Android ведет себя при запуске приложений с экрана HOME (или из списка доступных приложений) и при выборе задач из недавнего списка задач.
В первом случае (запуск приложения, выбирая его из списка доступных приложений или из ярлыка на экране HOME) создается пусковая установка Intent
с Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
. Это используется независимо от того, запущено ли приложение. Запускается Intent
, а затем ActivityManager
показывает, что делать.
Во втором случае (выбирая задачу из списка недавних задач), если задача все еще существует, она просто выводится на передний план. Задача "reset" НЕ выполняется, если задача просто перенесена на передний план, используя недавний список задач. Для меня не очевидно, как это управляется, и у меня не было возможности просмотреть исходный код, чтобы понять, почему это так.
Надеюсь, это ответит на ваши вопросы. Ждем ваших отзывов и результатов тестов.