- Tasks и Back Stack в Android
- Маленький итог
- Управление тасками
- Атрибут launchMode
- Флаги
- Affinity
- Чистка стека
- The Tasks API
- Handling task results
- Threading
- Activity-scoped listeners
- Chaining
- Blocking
- Interoperability
- Kotlin Coroutine
- Usage
- Guava ListenableFuture
- RxJava2 Observable
- Next steps
- Android Activity Launch Mode
- Tasks
- Back Stack
- 1. standard
- Example:
- 2. singleTop
- Example:
- Case 1:
- Case 2:
- 3. singleTask
- Example:
- Case 1:
- Case 2:
- 4. singleInstance
- Example:
- Case 1:
- Case 2:
- Intent Flags
- FLAG_ACTIVITY_NEW_TASK
- FLAG_ACTIVITY_CLEAR_TASK
- FLAG_ACTIVITY_SINGLE_TOP
- FLAG_ACTIVITY_CLEAR_TOP
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 и удалять из стека именно её
Это всё для данного топика. Статья не импровизированная, а по сути является вольным переводом официальной документации. Рекомендую собрать легкий пример и поэксперементировать с флагами и атрибутами. Некоторые моменты, лично для меня были, неожиданно интересными. любые ошибки и недоработки учту в лс. Спасибо.
Источник
The Tasks API
Starting with Google Play services version 9.0.0, you can use a Task API and a number of methods that return Task or its subclasses. Task is an API that represents asynchronous method calls, similar to PendingResult in previous versions of Google Play services.
Handling task results
To be notified when the task succeeds, attach an OnSuccessListener :
To be notified when the task fails, attach an OnFailureListener :
To handle success and failure in the same listener, attach an OnCompleteListener :
Threading
Listeners attached to a thread are run on the application main (UI) thread by default. When attaching a listener, you can also specify an Executor that is used to schedule listeners.
Activity-scoped listeners
If you are listening for task results in an Activity , you may want to add activity-scoped listeners to the task. These listeners are removed during the onStop method of your Activity so that your listeners are not called when the Activity is no longer visible.
Chaining
If you use multiple APIs that return Task , you can chain them together using a continuation. This helps avoid deeply nested callbacks and consolidates error handling for chains of tasks.
For example, the method doSomething returns a Task but requires an AuthResult , which we will get asynchronously from a task:
Using the Task.continueWithTask method, we can chain these two tasks:
Blocking
If your program is already executing in a background thread you can block a task to get the result synchronously and avoid callbacks:
You can also specify a timeout when blocking a task so that your application does not hang:
Interoperability
A Task aligns conceptually to several popular Android approaches to managing asynchronous code, and a Task can be straightforwardly converted to other primitives, including the ListenableFuture and Kotlin coroutines, which are recommended by AndroidX.
Here’s an example using a Task :
Kotlin Coroutine
Usage
Add the following dependency to your project and use the code below to convert from a Task .
Gradle (module-level build.gradle , usually app/build.gradle )
Snippet
Guava ListenableFuture
Add the following dependency to your project and use the code below to convert from a Task .
Gradle (module-level build.gradle , usually app/build.gradle )
Snippet
RxJava2 Observable
Add the following dependency, in addition to the relative async library of choice, to your project and use the code below to convert from a Task .
Gradle (module-level build.gradle , usually app/build.gradle )
Snippet
Next steps
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Источник
Android Activity Launch Mode
Jan 13, 2017 · 5 min read
Launch mode is an instruction for Android OS which specifies how the activity should be launched. It instructs how any new activity should be associated with the current task. Before moving further you first need to understand about very important topics-
Tasks
A task is a collection of activities that users interact with when performing a certain job. In general an application contains number of activities. Normally when user launch an application a new task will be created and the first activity instance is called root of the task.
When us e r launches an app from home icon, it navigates through different screens so different activities placed on the top of one another. This collection of activities is known as tasks.
Back Stack
Activities are arranged with the order in which each activity is opened. This maintained stack called Back Stack. When you start a new activity using startActivity(), it “pushes” a new activity onto your task, and put the previous Activity in the back stack.
Once you press back button then “pops” the top most activity and remove it from the back stack and taking you back to the previous activity.
Above figure explains representation of how each new activity in a task adds an item to the back stack. When the user presses the Back button, the current activity is destroyed and the previous activity resumes. For more details you can also refer .
There are four launch modes for activity. They are:
In the AndroidManifest you can use “launchMode” attribute inside the element to declare the activity’s launch mode like-
Now let’s look at the differences between launch modes.
1. standard
This is the default launch mode of an activity (If not specified). It creates a new instance of an activity in the task from which it was started. Multiple instances of the activity can be created and multiple instances can be added to the same or different tasks. In other words you can create the same activity multiple times in the same task as well as in different tasks.
Example:
Suppose you have A, B, C and D activities and your activity B has “launch mode = standard”. Now you again launching activity B –
State of Activity Stack before launch B
State of Activity Stack after launch B
2. singleTop
In this launch mode if an instance of activity already exists at the top of the current task, a new instance will not be created and Android system will route the intent information through onNewIntent(). If an instance is not present on top of task then new instance will be created.
Using this launch mode you can create multiple instance of the same activity in the same task or in different tasks only if the same instance does not already exist at the top of stack.
Example:
Case 1:
Suppose you have A, B and C activities and your activity D has “launch mode = singleTop”. Now you launching activity D —
State of Activity Stack before launch D
State of Activity Stack after launch D activity
A -> B -> C -> D (Here D launch as usual)
Case 2:
Suppose you have A, B, C and D activities and your activity D has “launch mode = singleTop”. Now you again launching activity D —
State of Activity Stack before launch D
State of Activity Stack after launch D activity
A -> B -> C -> D (Here old instance gets called and intent data route through onNewIntent() callback)
3. singleTask
In this launch mode a new task will always be created and a new instance will be pushed to the task as the root one. If an instance of activity exists on the separate task, a new instance will not be created and Android system routes the intent information through onNewIntent() method. At a time only one instance of activity will exist.
Example:
Case 1:
Suppose you have A, B and C activities and your activity D has “launch mode = singleTask”. Now you launching activity D —
State of Activity Stack before launch D
State of Activity Stack after launch D activity
A -> B -> C -> D (Here D launch as usual)
Case 2:
Suppose you have A, B, C and D activities and your activity B has “launch mode = singleTask”. Now you again launching activity B-
State of Activity Stack before launch D
State of Activity Stack after launch B activity
A -> B (Here old instance gets called and intent data route through onNewIntent() callback)
Also notice that C and D activities get destroyed here.
4. singleInstance
This is very special launch mode and only used in the applications that has only one activity. It is similar to singleTask except that no other activities will be created in the same task. Any other activity started from here will create in a new task.
Example:
Case 1:
Suppose you have A, B and C activities and your activity D has “launch mode = singleInstance”. Now you launching activity D —
State of Activity Stack before launch D
State of Activity Stack after launch D activity
Task2 — D (here D will be in different task)
Now if you continue this and start E and D then Stack will look like-
Task1 — A -> B -> C -> E
Case 2:
Suppose you have A, B, C activities in one task and activity D is in another task with “launch mode = singleInstance”. Now you again launching activity D-
State of Activity Stack before launch D
State of Activity Stack after launch B activity
Task2 — D (Here old instance gets called and intent data route through onNewIntent() callback)
Intent Flags
Android also provides Activity flags by which you can change the default behavior of Activity association with Tasks while starting it via startActivity() method. These flags values can be pass through Intent extra data.
FLAG_ACTIVITY_NEW_TASK
This flag works similar to “launchMode = singleTask”.
FLAG_ACTIVITY_CLEAR_TASK
This flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. The activity becomes the new root of an otherwise empty task, and any old activities are finished.
FLAG_ACTIVITY_SINGLE_TOP
This flag works similar to “launchMode = singleTop”.
FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
There are quite a lot on flags. You could find more about it at Intent.
Thanks for reading. To help others please click ❤ to recommend this article if you found it helpful.
Stay tuned for upcoming articles. For any quires or suggestions, feel free to hit me on Twitter Google+ LinkedIn
Check out my blogger page for more interesting topics on Software development.
Источник