В чем разница между FLAG_ACTIVITY_RESET_TASK_IF_NEEDED и FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP?
Я нахожусь в процессе (наконец) написания главы о задачах для моей книги, и я сталкиваюсь с несколькими затяжными головоломками.
Вещи, которые служат в качестве пусковых установок домашнего экрана, похоже, используют комбинацию FLAG_ACTIVITY_NEW_TASK
а также FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
когда они запускают запрошенную активность запуска:
Intent i=new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
i.setComponent(name);
startActivity(i);
Документация для FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
имеет:
Если установлено, и это действие либо запускается в новой задаче, либо выводится на вершину существующей задачи, то оно будет запущено как входная дверь задачи. Это приведет к применению любых сходств, необходимых для того, чтобы эта задача находилась в надлежащем состоянии (либо перемещение действий к ней), либо просто сброс ее в исходное состояние при необходимости.
Это не особенно понятно.
В частности, казалось бы, что те же самые эффекты можно было бы увидеть, используя комбинацию FLAG_ACTIVITY_CLEAR_TOP
а также FLAG_ACTIVITY_SINGLE_TOP
, Цитирование документов для FLAG_ACTIVITY_CLEAR_TOP
:
Если установлено, и запускаемое действие уже выполняется в текущей задаче, то вместо запуска нового экземпляра этого действия все остальные действия поверх него будут закрыты, и это намерение будет доставлено (теперь наверх) старая активность как новый Намерение...
Текущий запущенный экземпляр [требуемого действия] либо получит новое намерение, которое вы запускаете здесь, в своем методе onNewIntent(), либо само завершится и перезапустится с новым намерением. Если он объявил, что его режим запуска является "множественным" (по умолчанию), и вы не установили FLAG_ACTIVITY_SINGLE_TOP в том же намерении, то он будет завершен и создан заново; для всех других режимов запуска или если установлен FLAG_ACTIVITY_SINGLE_TOP, то это намерение будет доставлено в onNewIntent() текущего экземпляра.
FLAG_ACTIVITY_CLEAR_TOP
Документация имеет смысл, по крайней мере, для меня.
Итак, что же FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
сделать это отличается от комбинации FLAG_ACTIVITY_CLEAR_TOP
а также FLAG_ACTIVITY_SINGLE_TOP
?
Бонусные баллы, если вы можете объяснить, что FLAG_ACTIVITY_CLEAR_TASK
это отличается от любого из двух других вариантов, описанных выше.
Если он установлен в намерении, переданном в Context.startActivity(), этот флаг приведет к тому, что любая существующая задача, которая будет связана с действием, будет очищена перед началом действия. Таким образом, действие становится новым корнем в противном случае пустой задачи, и все старые действия завершаются. Это можно использовать только в сочетании с FLAG_ACTIVITY_NEW_TASK.
Одно очевидное различие между этим и FLAG_ACTIVITY_CLEAR_TOP
| FLAG_ACTIVITY_SINGLE_TOP
в том, что FLAG_ACTIVITY_CLEAR_TASK
потребности FLAG_ACTIVITY_NEW_TASK
, Но, кроме этого, может показаться, что чистые эффекты одинаковы, а также совпадают FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
,
3 ответа
Я взглянул на исходный код ActivityManager
, Флаг Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
действительно делает некоторую магию, которая Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
не делает: вызывает переопределение задачи.
Вот (хотя и неубедительный) пример:
В приложении А у нас есть корневой Активность RootA
и у нас есть еще одна активность 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
сейчас запускает активность ReparentableA
стандартным способом, без каких-либо специальных флагов. Экземпляр ReparentableA
создан и помещен поверх RootB
в текущей задаче.
Нажмите ДОМОЙ.
Теперь мы запускаем приложение A с экрана HOME. Это запускает новую задачу и создает новый экземпляр Activity RootA
как корневая активность в этой задаче. ПРИМЕЧАНИЕ. Когда Android запускает "намерение запуска", он автоматически устанавливает флаги Intent.FLAG_ACTIVITY_NEW_TASK
а также Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
, Из-за этого, запуск RootA
теперь запускает задачу по переопределению. Android проверяет, есть ли какие-либо действия в каких-либо других задачах, которые имеют сходство с этой новой задачей (и являются ремонтопригодными). Находит ReparentableA
(который имеет ту же близость задачи, что и RootA
) в задаче App B и переместит ее в новую задачу App A. При запуске приложения А мы не видим RootA
мы на самом деле видим ReparentableA
, так как он перемещен в начало новой задачи.
Если мы вернемся к приложению B, мы увидим, что ReparentableA
ушел из стека задач, и эта задача теперь состоит только из одного действия: RootB
,
Примечания по использованию Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
При использовании этих флагов для "сброса задачи" следует помнить, что он работает только в том случае, если в корне задачи уже есть экземпляр целевой операции. Если ваша корневая активность когда-либо заканчивается, вы не можете очистить свою задачу, запустив корневую активность с Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
, Android просто создаст новый экземпляр целевого (корневого) действия и поместит его поверх существующих действий в задаче, что, вероятно, совсем не то, что вам нужно.
Разница между Intent.FLAG_ACTIVITY_CLEAR_TASK
а также Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
:
Как отмечено выше, используя CLEAR_TOP | SINGLE_TOP
работает только в том случае, если в задании уже есть экземпляр целевой операции. CLEAR_TASK
однако удаляет все действия из задачи, независимо от того, был ли в задаче экземпляр целевого действия. Кроме того, используя CLEAR_TASK
гарантирует, что целевое действие становится корневым действием задачи, и вам не нужно знать, какое действие было корневым действием, прежде чем очистить задачу.
Разница между Intent.FLAG_ACTIVITY_CLEAR_TASK
а также Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
:
Как указано выше, используя CLEAR_TASK
всегда удаляет все действия из задачи и запускает новый экземпляр целевого действия. По сравнению, RESET_TASK_IF_NEEDED
сбросит задачу только в определенных ситуациях (часть "IF_NEEDED"). Задача "сбрасывается" только в том случае, если Android:
- Создание новой задачи (в этом случае функциональность "сброса" включает в себя переопределение задачи, описанное выше), или
- Если 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
выясняет, что делать.
Во втором случае (выбор задачи из списка недавних задач), если задача все еще существует, она просто переносится на передний план. Задача "сброс" НЕ выполняется, если задача только что выведена на передний план с использованием списка последних задач. Для меня не очевидно, как это делается, и у меня не было возможности просмотреть исходный код, чтобы выяснить, почему это так.
Я надеюсь, что это отвечает на ваши вопросы. Ждем ваших отзывов и результатов испытаний.
Я могу ошибаться здесь, но в моем понимании FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
анализирует все задачи и обеспечивает выполнение только одной задачи с активностью запуска.
FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP
будет проверять только текущую задачу, так что вы можете в конечном итоге запустить 2 экземпляра программы запуска (если первый был создан как отдельная задача).
1) FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Если какое-либо задание ожидает выполнения, оно уничтожит этот процесс и запустит запрошенное вами действие.
2) FLAG_ACTIVITY_CLEAR_TOP
Если выполняется какое-либо предыдущее намерение этого действия, этот метод доставит запущенный экземпляр действия, закроет все остальные действия и начнет выполнение с предыдущего экземпляра.
3) FLAG_ACTIVITY_SINGLE_TOP
Если недавно это действие было запущено, а экземпляр был сохранен, то он не запустит это действие.