Get back stack android

Tasks and the Back Stack

What actually happens when you tap the launcher icon for your app? If you said ‘my app launches’, you are technically correct, the best kind of correct. To dive in a bit deeper, it is helpful to understand what a task is and how it interacts with a little thing called the back button.

Tasks

A task is a collection of metadata and information around a stack of activities (you can see exactly what kind of data by looking at the RecentTaskInfo class).

So when you tap the launcher icon for your app, what the system is actually doing is looking for a previously existing task (determined by the Intent and Activity it points to) to resume — getting you back to exactly where you were. If no existing task is found, then a new task is created with your newly launched activity as the base activity on the task’s back stack.

Back Stack

As you might imagine, a task’s back stack is tied together with the back button, but it goes both ways. When you start a new activity using startActivity(), that is (by default) pushing a new activity onto your task, causing the previous Activity to be paused (and stopped if the new activity fully obscures the previous activity).

The back button (by default) then ‘pops’ the stack, calling finish() on the topmost activity, destroying it and removing it from the back stack and taking you back to the previous activity. This repeats until there’s nothing left in the back stack and you’re back at the launcher.

The Back Stack and Fragments

The back stack doesn’t apply only to activities: it also applies to fragments. When you provide a fragment transaction to add, replace, or remove a fragment from your UI, you can use addToBackStack() to effectively add the FragmentTransaction to the back stack.

This way when the back button is hit, the FragmentTransaction is reversed (an added fragment removed, a replaced fragment restored, or a removed fragment re-added). Each transaction added to the back stack is reversed in turn until they’re all removed at which time the default activity finishing behavior again kicks in.

Back isn’t the only navigation button

Of course, the back button isn’t the only navigation button on a modern Android device (no we don’t talk about the menu button anymore).

The home button is probably the most straightforward with its single focus: it puts the current task into the background, taking you back to your launcher.

Note: moving your task to the background does not kill your task (although the topmost activity is most certainly paused+stopped): it’ll live on until the process is killed. Learn more about process priorities and when your app can be killed in the ‘Who lives and who dies?’ blog post.

The overview button (formerly recents), takes you, as you might imagine, to the Overview screen. This is the ‘app switcher’ of the Android world — here you’ll see your most recent tasks and be able to select one to bring it back into the foreground.

Okay, that’s it. Nothing more to see.

Neat, startActivity() or addToBackStack() and the default back button behavior. Nothing special here, but nothing confusing either — these symmetric, consistent behavior serves as the defaults. In most cases, you should be using this default behavior.

Читайте также:  Phone search если андроид

Before you go running off and overriding onBackPressed() directly, there’s a few specific cases you might want to consider:

Preventing back button fatigue

Of course, the back button loses some of its luster when you need to press it 10+ times to get out where you are. One case where this is easy to avoid is when you are launching the same Activity you are currently on.

Instead of creating a stack of multiple copies of the same Activity (which is less fun both from a memory pressure perspective and back button fatigue), your Activity can use launchMode=”singleTop” in the Android manifest or you can add Intent.FLAG_ACTIVITY_SINGLE_TOP to your Intent.

This prevents multiple copies of the same Activity on the top of the back stack. Instead, you’ll get a callback to onNewIntent() with the new Intent and any extras.

Note: Read the documentation on onNewIntent() carefully: getIntent() will still return the original Intent unless you use setIntent() to override it.

The back stack and notifications

If you’re building a notification that points to an Activity deep within your app, there’s one case you want to avoid: tapping the back button exiting directly to the launcher. This occurs when the PendingIntent you provide starts a new task with just the one activity. And unless your notification is opening your launcher Activity, that’s not what you want. The user should be in the exact place they’d be as if they had navigated to that part of the app themselves. Your notification just saved them the intermediate steps.

For something so important, it would be nice to have a class that does all the work for you. Enter TaskStackBuilder: a class specifically for handling the flags and back stack for you for exactly this case:

You’ll notice use of the addNextIntentWithParentStack() method — this is the shortcut to building an entire task stack with just passing in the normal Intent you’d have created a PendingIntent from. It does have one requirement though: each Activity needs to have its parent Activity declared in the Android manifest (see the example from the docs).

And you don’t need to throw out TaskStackBuilder if the defaults don’t work in your case: editIntentAt() allows you to retrieve a specific Intent and set the action, set the data URI, or add extras. If you need even more customization, you can forgo using the *ParentStack() methods entirely and use addNextIntent() to directly add the exact Intents you need for your specific case.

Note: as mentioned in the docs, the other type of Activity you might launch from a notification is one specific to the Notification (i.e., not one in your normal application flow). An example of this might be Hangout’s Direct Reply-like Activity used prior to Android N. These activities are generally semi-transparent — you can see the other app below your Activity — and generally don’t have any synthetic back stack or new task associated with them.

Tasks and the back stack, working together

Remember the important part here is being predictable. If you’re messing with your back stack, make sure to test very thoroughly to ensure the best user experience.

Источник

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, существующий таск восстановится и продолжит свою работу.

Читайте также:  Root any android xda
Ниже покажу картинку, как работает стек.

Если продолжать нажимать кнопку 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 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.

Источник

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