- Tasks и Back Stack в Android
- Маленький итог
- Управление тасками
- Атрибут launchMode
- Флаги
- Affinity
- Чистка стека
- Очистите весь стек истории и запустите новое действие на Android
- ОТВЕТЫ
- Ответ 1
- Котлин
- Ответ 2
- Ответ 3
- Ответ 4
- Ответ 5
- Ответ 6
- Ответ 7
- Ответ 8
- Ответ 9
- Ответ 10
- Ответ 11
- Ответ 12
- Android: очистить стек действий
- 11 ответов
- Использование Kotlin:
- Очистите весь стек истории и начните новую деятельность на Android
- 10 ответов:
Tasks и Back Stack в Android
Итак. Каждое 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.
Маленький итог
Управление тасками
Существует два пути для изменения стандартной организации тасков. Мы можем устанавливать специальные атрибуты в манифесте для каждой Activity. Также мы можем устанавливать специальные флаги для Intent, который запускает новую Activity с помощью startActivity(). Заметьте, что иногда атрибуты в манифесте и флаги в Intent могут противоречить друг другу. В этом случаи флаги Intent будут более приоритетны.
Атрибут launchMode
Для каждой Activity в манифесте можно указать атрибут launchMode. Он имеет несколько значений:
- standard — (по умолчанию) при запуске Activity создается новый экземпляр в стеке. Activity может размещаться в стеке несколько раз
- singleTop — Activity может распологаться в стеке несколько раз. Новая запись в стеке создается только в том случаи, если данная Activity не расположена в вершине стека. Если она на данный момент является вершиной, то у нее сработает onNewIntent() метод, но она не будет пересоздана
- singleTask — создает новый таск и устанавливает Activity корнeвой для него, но только в случаи, если экземпляра данной Activity нет ни в одном другом таске. Если Activity уже расположена в каком либо таске, то откроется именно тот экземпляр и вызовется метод onNewIntent(). Она в свое время становится главной, и все верхние экземпляры удаляются, если они есть. Только один экземпляр такой Activity может существовать
- singleInstance — тоже что и singleTask, но для данной Activity всегда будет создаваться отдельный таск и она будет в ней корневой. Данный флаг указывает, что Activity будет одним и единственным членом своего таска
На самом деле не важно, в каком таске открыта новая Activity. При нажатии кнопки back мы все равно вернемся на предыдущий таск и предыдущие Activity. Единственный момент, который нужно учитывать — это параметр singleTask. Если при открытии такой Activity мы достанем ее из другого background таска, то мы полностью переключаемся на него и на его стек. на картинке ниже это продемонстрировано.
Флаги
Как и говорил, мы можем устанавливать специальный флаги для Intent, который запускает новую Activity. Флаги более приоритетны, чем launchMode. Существует несколько флагов:
- FLAG_ACTIVITY_NEW_TASK — запускает Activity в новом таске. Если уже существует таск с экземпляром данной Activity, то этот таск становится активным, и срабатываем метод onNewIntent().
Флаг аналогичен параметру singleTop описанному выше - FLAG_ACTIVITY_SINGLE_TOP — если Activity запускает сама себя, т.е. она находится в вершине стека, то вместо создания нового экземпляра в стеке вызывается метод onNewIntent().
Флаг аналогичен параметру singleTop описанному выше - FLAG_ACTIVITY_CLEAR_TOP — если экземпляр данной Activity уже существует в стеке данного таска, то все Activity, находящиеся поверх нее разрушаются и этот экземпляр становится вершиной стека. Также вызовется onNewIntent()
Affinity
Стандартно все Activity нашего приложения работают в одном таске. По желанию мы можем изменять такое поведение и указывать, чтобы в одном приложении Activity работали в разных тасках, или Activity разных приложений работали в одном. Для этого мы можем в манифесте для каждой Activity указывать название таска параметром taskAffinity. Это строковое значение, которое не должно совпадать с названием package, т.к. стандартный таск приложения называется именно как наш пакет. В общем случаи данный параметр указывает, что Activity будет гарантированно открываться в своём отдельном таске. Данный параметр актуален, если мы указываем флаг FLAG_ACTIVITY_NEW_TASK или устанавливаем для Activity атрибут allowTaskReparenting=«true». Этот атрибут указывает, что Activity может перемещаться между тасками, который её запустил и таском, который указан в taskAffinity, если один из них становится активным.
Чистка стека
Если таск долгое время находится в background, то система сама чистит его стек, оставляя только корневую Activity. Данное поведение обусловлено тем, что пользователь может забыть, что он делал в приложении до этого и скорее всего зашел в него снова уже с другой целью. Данная логика также может быть изменена с помощью нескольких атрибутов в манифесте.
- alwaysRetainTaskState — если флаг установлен в true для корневой Activity, то стек не будет чиститься и полностью восстановится даже после длительного времени
- clearTaskOnLaunch — если установить флаг в true для корневой Activity, то стек будет чиститься моментально, как только пользователь покинет таск. Полная противоположность alwaysRetainTaskState
- finishOnTaskLaunch — работает аналогично clearTaskOnLaunch, но может устанавливаться на любую Activity и удалять из стека именно её
Это всё для данного топика. Статья не импровизированная, а по сути является вольным переводом официальной документации. Рекомендую собрать легкий пример и поэксперементировать с флагами и атрибутами. Некоторые моменты, лично для меня были, неожиданно интересными. любые ошибки и недоработки учту в лс. Спасибо.
Источник
Очистите весь стек истории и запустите новое действие на Android
Можно ли запустить действие в стеке, очистив всю историю до него?
Ситуация
У меня есть стек активности, который либо идет A- > B- > C, либо B- > C (экран A выбирает токен пользователя, но у многих пользователей есть только один токен).
На экране C пользователь может выполнить действие, которое делает экран B недействительным, поэтому приложение хочет отобразить их на экране A, независимо от того, находится ли он в стеке. Экран A должен быть единственным элементом в стеке в моем приложении.
Примечания
Есть много других подобных вопросов, но я не нашел ничего, что отвечает на этот точный вопрос. Я попробовал позвонить getParent().finish() — это всегда приводит к исключению нулевого указателя. FLAG_ACTIVITY_CLEAR_TOP работает только в том случае, если активность уже находится в стеке.
ОТВЕТЫ
Ответ 1
На уровне API 11 новый флаг намерений был добавлен только для этого: Intent.FLAG_ACTIVITY_CLEAR_TASK
Просто чтобы уточнить, используйте это:
Котлин
К сожалению, для API lvl & lt; = 10 я еще не нашел чистого решения для этого. Решение «DontHackAndroidLikeThis» действительно является чистой взломом. Вы не должны этого делать. 🙂
Изменить: Согласно комментарию @Бена Пирсона, для API & lt; = 10 теперь можно использовать класс IntentCompat для того же самого. Для очистки задачи можно использовать флаг IntentCompat.FLAG_ACTIVITY_CLEAR_TASK . Таким образом, вы также можете поддерживать предварительный уровень API 11.
Ответ 2
Случай 1: Только два действия A и B:
Здесь поток активности A- > B. При щелчке по кнопке от B нам нужно закрыть приложение, а затем при запуске Activity B из A just call finish() это предотвратит сохранение андроидом активности A в Backstack.eg для активностью A является экран Loding/Splash приложения.
Случай 2: более двух действий:
Если есть поток, подобный A- > B- > C- > D- > B, и нажатием кнопки возврата в действии B при поступлении из действия D. В этом случае мы должны использовать.
Здесь активность B запускается из backstack, а не из нового экземпляра из-за Intent.FLAG_ACTIVITY_CLEAR_TOP и Intent.FLAG_ACTIVITY_NEW_TASK очищает стек и делает его верхним. Поэтому, когда мы нажимаем кнопку «Назад», вся заявка будет завершена.
Ответ 3
С новой версией Android >= API 16 используйте finishAffinity()
подходит для >= API 16.
- Это то же самое, что и запуск новой Activity, и очистка всего стека.
- ИЛИ Перезапустить в MainActivity/FirstActivity.
Ответ 4
Я тоже потратил несколько часов на это. и согласен с тем, что FLAG_ACTIVITY_CLEAR_TOP звучит так, как вам хотелось бы: очистить весь стек, кроме запуска активности, поэтому кнопка «Назад» выходит из приложения. Однако, как отметил Майк Репасс, FLAG_ACTIVITY_CLEAR_TOP работает только тогда, когда запущенная вами деятельность уже находится в стеке; когда активность не существует, флаг ничего не делает.
Что делать? Поместите запущенную деятельность в стек с FLAG_ACTIVITY_NEW_TASK, что делает эту деятельность началом новой задачи в стеке истории. Затем добавьте флаг FLAG_ACTIVITY_CLEAR_TOP.
Теперь, когда FLAG_ACTIVITY_CLEAR_TOP отправляется на поиск нового действия в стеке, он будет там и будет остановлен, прежде чем все остальное будет очищено.
Здесь моя функция выхода; параметр View — это кнопка, к которой прикреплена функция.
Ответ 5
Вы не должны менять стек. Кнопка Android back должна работать как в веб-браузере.
Я могу придумать способ сделать это, но это довольно взломать.
Сделайте свои действия singleTask , добавив его в AndroidManifest Пример:
Расширьте Application , который будет придерживаться логики того, куда идти.
и откройте обратную кнопку pop() из стека.
Еще раз вы не должны этого делать:)
Ответ 6
Сразу после запуска нового действия с помощью startActivity убедитесь, что вы вызываете finish() , чтобы текущая активность не была уложена за новой.
Ответ 7
Ответ 8
Ответ 9
Попробуйте код ниже,
Ответ 10
Для меня ни один из вышеперечисленных методов не работает.
Просто сделайте это, чтобы очистить все предыдущие действия:
Ответ 11
Я нашел слишком простой хак, просто добавьте новый элемент в AndroidManifest как: —
android:noHistory очистит вашу нежелательную активность от Stack.
Ответ 12
Иногда ваш эмулятор android может не подключиться к инструменту DDL eclipse и попросить запустить adb вручную. В этом случае вы можете запустить или остановить adb с помощью командной строки.
Источник
Android: очистить стек действий
В моем приложении есть несколько действий. и поток очень сложный. Когда я нажимаю кнопку выхода, приложение переходит на экран входа в систему, и оттуда пользователь может выйти, нажав кнопку отмены (вызов system.exit(0) )
Когда я выхожу или нажимаю кнопку возврата, система вызывает действие из стека 🙁 как я могу очистить все действия в стеке, когда я дохожу до экрана входа в систему? Вызов finish() нецелесообразен, так как существует так много действий и некоторые действия не должны закрываться, когда они активны, например, когда активна собственная камера.
11 ответов
Большинство из вас ошибаются. Если вы хотите закрыть существующий стек активности независимо от того, что там находится, и создать новый корень, правильный набор флагов будет следующим:
public static final int FLAG_ACTIVITY_CLEAR_TASK
Добавлено в API уровня 11
Если установлено намерение, переданное в Context.startActivity() , этот флаг вызовет любую существующую задачу, которая будет связан с действием, которое нужно очистить до того, как деятельность начата. То есть деятельность становится новым корнем в противном случае задание будет пустым, а все старые действия будут завершены. Это может может использоваться только вместе с FLAG_ACTIVITY_NEW_TASK .
Намерение намерения = новое намерение (LoginActivity.this, MainActivity.class); intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity (намерение); финиш();
Использование Kotlin:
Вы можете установить флаг напрямую, используя метод установки. В Kotlin or — это замена побитовой Java или | .
Если вы планируете использовать это регулярно, создайте функцию расширения Intent
Затем вы можете напрямую вызвать эту функцию перед началом
Для разработчиков Xamarin вы можете использовать:
Это решение работает нормально:
Но новая активность запускается долго, и какое-то время вы видите белый экран. Если это критично, используйте этот обходной путь:
Как это использовать:
Недостаток: все действия, которые должны быть закрыты в стеке, должны расширять BaseActivity.
Я заметил, что вы запросили решение, которое не зависит от finish() , но мне интересно, может ли это все же помочь.
Я отслеживал, поднимается ли флаг выхода с помощью статической переменной класса, которая сохраняется в течение всего срока службы приложения. В каждом релевантном действии onResume() используйте
Источник
Очистите весь стек истории и начните новую деятельность на Android
можно ли начать действие в стеке, очистив перед ним всю историю?
ситуация
у меня есть стек действий, который либо идет A->B->C, либо B — >C (экран a выбирает токен пользователей, но у многих пользователей есть только один токен).
в экране C пользователь мая выполните действие, которое делает экран B недействительным, поэтому приложение хочет вывести их на экран A, независимо от того, находится ли он уже внутри стек. Экран A должен быть единственным элементом в стеке в моем приложении.
Примечания
есть много других подобных вопросов, но я не нашел ничего, что отвечает на этот точный вопрос. Я пытался дозвониться getParent().finish() — это всегда приводит к исключению нулевого указателя. FLAG_ACTIVITY_CLEAR_TOP работает только в том случае, если действие уже находится в стеке.
10 ответов:
в API level 11 был добавлен новый флаг намерения именно для этого:намерениях.FLAG_ACTIVITY_CLEAR_TASK
просто чтобы уточнить, используйте это:
к сожалению для API lvl «DontHackAndroidLikeThis» решение это действительно чистый хакерство. Вы не должны этого делать. 🙂
Edit: Согласно @Бен Пирсон’s комментарий, для API IntentCompat класс для того же. Можно использовать IntentCompat.FLAG_ACTIVITY_CLEAR_TASK флаг для очистки задачи. Таким образом, вы также можете поддерживать pre API level 11.
Случай 1: только два вида деятельности A и B:
здесь поток активности-это A — >B .При нажатии кнопки «назад» из B нам нужно закрыть приложение, а затем при запуске Activity B с помощью just call finish() это предотвратит сохранение Android активности A в Backstack.eg для активности A-это размещение / заставка приложения.
случай 2: более двух видов деятельности:
Если есть поток, как A — >B — >C — >D — >B и on нажав кнопку «Назад» в деятельности B, а поступающие от деятельности Д. В этом случае мы должны использовать.
здесь действие B будет запущено из backstack, а не из нового экземпляра из-за намерения.FLAG_ACTIVITY_CLEAR_TOP и намерение.FLAG_ACTIVITY_NEW_TASK очищает стек и делает его верхним one.So когда мы нажимаем кнопку назад, все приложение будет прекращено.
С новой версией Android >= API 16 use finishAffinity()
подход подходит для > = API 16.
- это то же самое, что начать новую деятельность, и очистить весь стек.
- или перезапустить в MainActivity / FirstActivity.
Я тоже потратил на это несколько часов . и согласитесь, что FLAG_ACTIVITY_CLEAR_TOP звучит так, как вы хотите: очистить весь стек, за исключением запускаемой активности, поэтому кнопка «Назад» выходит из приложения. Тем не менее, как упоминал Майк Репасс, FLAG_ACTIVITY_CLEAR_TOP работает только тогда, когда активность, которую вы запускаете, уже находится в стеке; когда активности нет, флаг ничего не делает.
Что делать? Поместите запускаемое действие в стек с помощью FLAG_ACTIVITY_NEW_TASK, что делает это действие началом новой задачи в стеке истории. Затем добавьте флаг FLAG_ACTIVITY_CLEAR_TOP.
теперь, когда FLAG_ACTIVITY_CLEAR_TOP идет, чтобы найти новую активность в стеке, он будет там и будет вытащен до того, как все остальное будет очищено.
вот моя функция выхода из системы; параметр View-это кнопка, к которой прикреплена функция.
вы не должны менять стек. Кнопка Android back должна работать как в веб-браузере.
Я могу придумать способ сделать это, но это довольно рубить.
Сделайте свою деятельность singleTask добавив его в AndroidManifest Пример:
расширения Application , который будет содержать логику, куда идти.
и отрегулируйте кнопку Назад к pop() из стека.
еще раз, вы не должны этого делать 🙂
сразу после начала нового действия, используя startActivity , убедитесь, что вы называете finish() Так что текущая активность не укладывается за новой.
Источник