Android clear fragment backstack

Managing the Fragment Back Stack

Jun 1, 2016 · 3 min read

Or: A lesson in not fighting the framework

The Android framework provides simple APIs for managing your back stack without headache for most simple applications. However at some point you are likely going to run into a situation that doesn’t quite fit the mold of a an application with a simple back stack.

Take, for example, an app that uses bottom navigation. If we start on Tab 1, drill down to a sub screen, then switch to Tab 2, we may want to pop off all the subscreens on Tab 1 before switching to the second tab.

If y ou want to jump right to the sample code, you can find it here on GitHub.

Fighting the framework

In Advocating Against Android Fragments, Pierre-Yves Ricau teaches an important lesson- there’s nothing particularly magical about the Android framework’s back stack. You can manage the back navigation of your application however you want, with or without the framework.

This is true, and you shouldn’t be afraid to manage the back stack yourself if the framework simply isn’t going to work in your scenario. Before you do that, however, make sure you understand the framework and how it can work for you.

One solution: manage the backstack yourself

Here is one way to handle popping off a certain subset of the backstack yourself by keeping track of how many “subscreens” are on the stack:

When I used this approach, I ran into a few quirks that I didn’t like.

First and foremost, it isn’t flexible. What if you add another “level” of back stack management into your app? Then you need to keep track of that too. Going back partway through the stack isn’t particularly easy with this approach.

The other quirk I didn’t like with this approach was that when calling popBackStackImmediate() in succession , each intermediate Fragment is resumed very briefly. This resulted in some code executing for a Fragment that wasn’t visible and wasn’t going to be visible.

Working with the Framework

As it turns out, the Android framework offers a solution that works very well for this and many other situations.

When adding a Fragment to the back stack, Android developers most commonly use addToBackStack(null). Why do we always pass in null? It turns out we can pass in something else that makes the Fragment back stack much more useful.

Tags and names

Fragment transactions can involve two different types of tags. The one that most Android developers are familiar with is the Fragment tag, which you can use to find a specific Fragment in your FragmentManager later via findFragmentByTag(). This is useful for finding a Fragment when your application is in a particular state, but keep in mind that the Fragment needs to be added to your FragmentManager. If you have removed() or replaced() a Fragment and haven’t added it to the backstack, you won’t be able to find it.

The other type of tag is the BackStackRecord’s name passed in to addToBackStack(). This name identifies a particular back stack record, which is a record of what occurred in a particular transaction. popBackStackImmediate() and its counterparts have variants that accept a back stack record name to pop the back stack to a particular state.

The back stack tag solution

Here’s how to solve our problem with back stack tags. I’m actually just going to be using one tag, which identifies the current “first level” Fragment (tab) on the stack.

With this code, the back stack just manages itself! We don’t need to tell it to pop are the right time or keep track of what Fragments we have added.

Inclusive vs Exclusive

There’s one last thing to note in my example, and that’s the use of FragmentManager.POP_BACK_STACK_INCLUSIVE. This tells the FragmentManager to pop our root Fragment state along with everything else. In my example this means that the current tab also gets popped off, creating a clean slate for the new tab we are about to display.

Читайте также:  Как соединить наушники беспроводные с андроидом

The other option is to pass in zero, which will pop everything up to the specified state. In my example this would leave the current tab on the backstack, so hitting back after navigating to a tab would bring you back to the previous tab.

Источник

Очистить задний стек с помощью фрагментов

я портировал свое приложение для Android на honeycomb, и я сделал большой рефакторинг, чтобы использовать фрагменты. В моей предыдущей версии, когда я нажал кнопку Home я использовал, чтобы сделать ACTIVITY_CLEAR_TOP для того, чтобы сбросить резервную стопку.

Теперь мое приложение-это всего лишь одно действие с несколькими фрагментами, поэтому, когда я нажимаю кнопку Home, я просто заменяю один из фрагментов внутри него. Как я могу очистить свой задний стек без использования startActivity С ACTIVITY_CLEAR_TOP флаг?

12 ответов:

из ответа Иоахима, от Диана Hackborn:

Я закончил тем, что просто использовал:

но мог бы также использовать что-то вроде:

который выведет все состояния до названного. Затем вы можете просто заменить фрагмент на то, что вы хотите

чтобы сделать ответ на комментарий @Warpzit и сделать его легче для других, чтобы найти.

при всем уважении ко всем вовлеченным сторонам; я очень удивлен, увидев, как многие из вас могут очистить весь фрагмент обратно стека с помощью простого

По данным документация для Android (относительно name аргумент — «null» в заявленных рабочих предложениях).

Если null, только верхнее состояние выскочил

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

(для справки, что-то вместе с этим)

принятого ответа мне было недостаточно. Я должен был использовать:

работает для меня и простой способ без использования цикла:

очистить backstack без петель

здесь имя является параметром addToBackStack ()

выскакивая из backstack, используя следующие

Это просто удаление фрагментов из транзакции, ни в коем случае он не собирается удалять фрагмент с экрана. Так что в идеале он может быть не виден вам, но может быть два или три фрагмента сложены друг на друга,а при нажатии клавиши «Назад» пользовательский интерфейс может выглядеть загроможденным, сложенным.

просто простой пример:-

Предположим, у вас есть fragmentA, который загружает фрагмента B, используя fragmentmanager.заменить() и затем мы делаем addToBackStack, чтобы сохранить эту транзакцию. Таким образом, поток:—

Шаг 1 — > FragmentA — >FragmentB (мы перешли к FragmentB, но фрагмент A находится в фоновом режиме, не видно).

теперь вы выполняете некоторую работу в fragmentB и нажимаете кнопку Save-которая после сохранения должна вернуться к fragmentA.

Шаг 2 — > на сохранение Фрагментб, мы возвращаемся к фрагменту.

Шаг 3 — > Так что распространенная ошибка будет. во фрагменте B мы сделаем диспетчер фрагментов.заменить () fragmentB на fragmentA.

но что на самом деле происходит, мы снова загружаем фрагмент A, заменяя Фрагментb . Итак, теперь есть два фрагмента (один из Шага-1, и один из этого шага-3).

два экземпляра FragmentsA сложены друг на друга, которые могут быть не видны , но они есть.

Так что даже если мы очистим backstack вышеуказанными методами, транзакция будет очищена, но не фактические фрагменты. Так что в идеале в таком конкретном случае, при нажатии кнопки save вам просто нужно вернуться к fragmentA, просто сделав fm.popBackStack () или fm.popBackImmediate ().

поэтому правильный шаг 3 — > fm.popBackStack () вернитесь к фрагменту, который уже находится в памяти.

чтение документация и изучая, что такое идентификатор фрагмента, он кажется просто индексом стека, поэтому это работает:

ноль ( 0 ) — это нижняя часть стека, поэтому выскакивание до нее включительно очищает стек.

предостережение: хотя вышеизложенное работает в моей программе, я немного сомневаюсь, потому что документация FragmentManager никогда не утверждает, что идентификатор является индексом стека. Это имеет смысл, что это будет, и все мои отладки бревна обнажают, что это такое, но, возможно, в каких-то особых обстоятельствах этого не будет? Может ли кто-нибудь подтвердить это так или иначе? Если это так, то это лучшее решение. Если нет, то это вариант:

Читайте также:  Русские телеканалы для андроид

просто используйте этот метод и передайте тег Context & Fragment, до которого нам нужно удалить фрагменты backstake.

использование

Источник

Android Fragment Back Stack Example

Android OS provides a back stack function for Activity, it also provides the back stack function for Fragment. If you add one Fragment into the back stack, when you press the android device back menu, you can find the Fragment that is saved in the back stack popup. Until all the saved Fragments in the back stack popup, then the activity will exit.

1. Fragment Back Stack Example.

  1. This example contains one activity and three fragments.
  2. Each fragment includes a button and an input text box.
  3. When clicking the button it will either show a hidden or create a new target fragment.
  4. When clicking the back menu, the stacked fragments will be popup by order, if the fragment is hidden in the stack ( fragment two ), then the text in the input box will be saved also.
  5. If the fragment is replaced in the stack ( fragment one ), because the replace action will delete the previous fragment ( fragment one ) and then add a new fragment ( fragment two ), so the input text in the previous fragment will not be saved.
  6. You can use the below code to put a fragment into the back stack.
  7. If you click the “Go To Fragment One” button in Fragment three, because Fragment one is at the bottom of the back stack, so it will remove all the above Fragments in the back stack and show Fragment One again.
  8. So when you go to Fragment Two again, you will find the input text disappear because it is newly created.

Источник

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 и удалять из стека именно её

Это всё для данного топика. Статья не импровизированная, а по сути является вольным переводом официальной документации. Рекомендую собрать легкий пример и поэксперементировать с флагами и атрибутами. Некоторые моменты, лично для меня были, неожиданно интересными. любые ошибки и недоработки учту в лс. Спасибо.

Источник

Оцените статью