Zadanie to zbiór aktywności, z którymi użytkownicy wchodzą w interakcję, gdy próbują coś zrobić w aplikacji. Te aktywności są ułożone w stosie nazywanym stosem wstecznym w kolejności, w jakiej są otwierane.
Na przykład aplikacja do poczty e-mail może mieć jedną aktywność, która wyświetla listę nowych wiadomości. Gdy użytkownik wybierze wiadomość, otworzy się nowa aktywność, w której będzie można ją wyświetlić. Nowa aktywność jest dodawana do stosu wstecznego. Gdy użytkownik kliknie lub wykona gest Wstecz, nowa aktywność zostanie zakończona i usunięta ze stosu.
Cykl życia zadania i jego stosu wstecznego
Ekran główny urządzenia jest punktem wyjścia dla większości zadań. Gdy użytkownik kliknie ikonę aplikacji lub skrótu w Menu z aplikacjami lub na ekranie głównym, zadanie tej aplikacji zostanie przeniesione na pierwszy plan. Jeśli nie ma zadania dla aplikacji, tworzone jest nowe zadanie, a główne działanie tej aplikacji otwiera się jako działanie główne na stosie.
Gdy bieżąca aktywność uruchamia inną, nowa aktywność jest umieszczana na górze stosu i jest aktywna. Poprzednia aktywność pozostaje na stosie, ale jest zatrzymana. Gdy aktywność zostanie zatrzymana, system zachowa bieżący stan interfejsu. Gdy użytkownik wykona działanie wstecz, bieżąca aktywność zostanie usunięta ze stosu i zniszczona. Poprzednia aktywność zostanie wznowiona, a poprzedni stan jej interfejsu zostanie przywrócony.
Aktywności na stosie nigdy nie są zmieniane, tylko wypychane po uruchomieniu i usuwane po zamknięciu przyciskiem lub gestem Wstecz. Dlatego stos wsteczny działa w strukturze ostatni na wejściu, pierwszy na wyjściu, jak pokazano na rysunku 1.
Gdy użytkownik klika lub wykonuje gest Wstecz, każda aktywność na stosie jest usuwana, aby odsłonić poprzednią, aż użytkownik wróci do ekranu głównego lub do aktywności, która była uruchomiona, gdy zadanie się rozpoczęło. Gdy wszystkie aktywności zostaną usunięte ze stosu, zadanie przestanie istnieć.
Działanie po dwukrotnym dotknięciu tyłu urządzenia w przypadku aktywności w głównym menu z aplikacjami
Aktywności głównego menu z aplikacjami to aktywności, które deklarują filtr intencji z ACTION_MAIN i CATEGORY_LAUNCHER. Te aktywności są wyjątkowe, ponieważ działają jako punkty wejścia do aplikacji z menu z aplikacjami i służą do rozpoczynania zadania.
Gdy użytkownik kliknie lub wykona gest Wstecz w głównej aktywności programu uruchamiającego, system obsłuży zdarzenie inaczej w zależności od wersji Androida na urządzeniu.
- Działanie systemu na Androidzie 11 i starszych wersjach
- System kończy aktywność.
- Działanie systemu na Androidzie 12 i nowszych
System przenosi aktywność i jej zadanie do tła, zamiast kończyć aktywność. Jest to zgodne z domyślnym działaniem systemu podczas opuszczania aplikacji za pomocą przycisku lub gestu ekranu głównego.
W większości przypadków oznacza to, że użytkownicy mogą szybciej wznowić działanie aplikacji ze stanu ciepłego, zamiast całkowicie uruchamiać ją ponownie ze stanu zimnego.
Jeśli chcesz zapewnić niestandardowe przechodzenie wstecz, zalecamy użycie interfejsów API aktywności AndroidX zamiast zastępowania metody
onBackPressed(). Interfejsy API aktywności AndroidX automatycznie odwołują się do odpowiedniego zachowania systemu, jeśli nie ma komponentów przechwytujących systemowe kliknięcie przycisku Wstecz.Jeśli jednak aplikacja zastępuje metodę
onBackPressed(), aby obsługiwać przechodzenie wstecz i kończyć aktywność, zaktualizuj implementację, aby wywoływać metodęsuper.onBackPressed()zamiast kończyć aktywność. Wywołanie metodysuper.onBackPressed()przenosi aktywność i jej zadanie do tła, gdy jest to konieczne, i zapewnia użytkownikom bardziej spójne działanie nawigacji w aplikacjach.
Zadania w tle i na pierwszym planie
Zadanie to spójna jednostka, która może zostać przeniesiona do tła, gdy użytkownik rozpocznie nowe zadanie lub przejdzie na ekran główny. Gdy zadanie jest w tle, wszystkie jego aktywności są zatrzymane, ale stos wsteczny zadania pozostaje nienaruszony – zadanie traci zaznaczenie, gdy wykonywane jest inne zadanie, jak pokazano na rysunku 2. Zadanie może następnie powrócić na pierwszy plan, aby użytkownicy mogli kontynuować pracę od miejsca, w którym ją przerwali.
Rozważmy ten przepływ zadań dla bieżącego zadania A, które ma na stosie 3 aktywności, w tym 2 pod bieżącą aktywnością:
Użytkownik naciska przycisk ekranu głównego lub wykonuje gest, a następnie uruchamia nową aplikację z menu z aplikacjami.
Gdy pojawi się ekran główny, zadanie A przejdzie w tło. Gdy uruchamia się nowa aplikacja, system rozpoczyna zadanie dla tej aplikacji (zadanie B) z własnym stosem aktywności.
Po interakcji z tą aplikacją użytkownik ponownie wraca do ekranu głównego i wybiera aplikację, która pierwotnie uruchomiła zadanie A.
Teraz zadanie A pojawia się na pierwszym planie – wszystkie 3 aktywności na stosie są nienaruszone, a aktywność na górze stosu zostaje wznowiona. W tym momencie użytkownik może też wrócić do zadania B, przechodząc na ekran główny i wybierając ikonę aplikacji, która rozpoczęła to zadanie, lub wybierając zadanie aplikacji na ekranie ostatnio używanych aplikacji.
Wiele instancji aktywności
Działania na stosie wstecznym nigdy nie są zmieniane, więc jeśli aplikacja umożliwia użytkownikom rozpoczęcie określonego działania z więcej niż 1 działania, tworzona jest nowa instancja tego działania i jest ona umieszczana na stosie, zamiast przenosić poprzednią instancję działania na górę. W związku z tym jedna aktywność w aplikacji może być tworzona wielokrotnie, nawet w ramach różnych zadań, jak pokazano na rysunku 3.
Jeśli użytkownik cofnie się za pomocą przycisku lub gestu Wstecz, instancje aktywności zostaną wyświetlone w kolejności, w jakiej zostały otwarte, każda z własnym stanem interfejsu. Możesz jednak zmienić to zachowanie, jeśli nie chcesz, aby aktywność była tworzona więcej niż raz. Więcej informacji znajdziesz w artykule Zarządzanie zadaniami.
Środowiska z wieloma oknami
Gdy aplikacje działają jednocześnie w trybie wielu okien, który jest obsługiwany na Androidzie 7.0 (poziom interfejsu API 24) i nowszych wersjach, system zarządza zadaniami osobno dla każdego okna. W każdym oknie może być kilka zadań. To samo dotyczy aplikacji na Androida działających na Chromebookach: system zarządza zadaniami lub grupami zadań na poziomie okna.
Podsumowanie cyklu życia
Podsumowanie domyślnego działania aktywności i zadań:
Gdy aktywność A uruchamia aktywność B, aktywność A zostaje zatrzymana, ale system zachowuje jej stan, np. pozycję przewijania i tekst wpisany w formularzach. Jeśli użytkownik kliknie lub użyje gestu Wstecz w aktywności B, aktywność A zostanie wznowiona z przywróconym stanem.
Gdy użytkownik opuści zadanie za pomocą przycisku ekranu głównego lub gestu, bieżąca aktywność zostanie zatrzymana, a zadanie przejdzie w tło. System zachowuje stan każdej aktywności w zadaniu. Jeśli użytkownik później wznowi zadanie, wybierając ikonę programu uruchamiającego, która je rozpoczęła, zadanie zostanie przeniesione na pierwszy plan i wznowi aktywność na górze stosu.
Jeśli użytkownik kliknie lub wykona gest Wstecz, bieżąca aktywność zostanie usunięta ze stosu i zniszczona. Poprzednia aktywność na stosie zostanie wznowiona. Gdy aktywność zostanie zniszczona, system nie zachowuje jej stanu.
To działanie różni się w przypadku aktywności w głównym menu z uprawnieniami roota na Androidzie 12 (poziom API 31) i nowszych wersjach.
Aktywności można tworzyć wielokrotnie, nawet z innych zadań.
Zarządzanie zadaniami
Android zarządza zadaniami i stosem wstecznym, umieszczając wszystkie aktywności uruchomione po sobie w tym samym zadaniu, na stosie typu „ostatni na wejściu, pierwszy na wyjściu”. To rozwiązanie sprawdza się w przypadku większości aplikacji i zwykle nie musisz się martwić o to, jak aktywności są powiązane z zadaniami ani jak istnieją na stosie wstecznym.
Możesz jednak zdecydować, że chcesz przerwać normalne działanie. Możesz na przykład chcieć, aby aktywność w aplikacji rozpoczynała nowe zadanie, zamiast być umieszczana w bieżącym zadaniu. Możesz też chcieć, aby po rozpoczęciu aktywności została wyświetlona jej istniejąca instancja, zamiast tworzyć nową instancję na stosie wstecznym. Możesz też chcieć, aby po opuszczeniu zadania przez użytkownika stos wsteczny został wyczyszczony ze wszystkich aktywności z wyjątkiem aktywności głównej.
Możesz to zrobić, używając atrybutów w elemencie manifestu <activity> i flag w intencji przekazywanej do startActivity().
Oto główne atrybuty <activity>, których możesz używać do zarządzania zadaniami:
taskAffinitylaunchModeallowTaskReparentingclearTaskOnLaunchalwaysRetainTaskStatefinishOnTaskLaunch
Oto główne flagi intencji, których możesz używać:
W sekcjach poniżej opisano, jak używać tych atrybutów pliku manifestu i flag intencji, aby określić, jak aktywności są powiązane z zadaniami i jak zachowują się na stosie wstecznym.
W sekcjach poniżej opisano też, jak system przedstawia zadania i aktywności na ekranie Ostatnie oraz jak nimi zarządza. Zwykle to system określa, jak zadania i aktywności są reprezentowane na ekranie ostatnich aplikacji, i nie trzeba tego zmieniać. Więcej informacji znajdziesz w artykule o ekranie Ostatnie (w języku angielskim).
Definiowanie trybów uruchamiania
Tryby uruchamiania pozwalają określić, jak nowa instancja aktywności jest powiązana z bieżącym zadaniem. Tryby uruchamiania możesz definiować na 2 sposoby, które opisujemy w tych sekcjach:
-
Gdy deklarujesz aktywność w pliku manifestu, możesz określić, jak aktywność ma być powiązana z zadaniem po uruchomieniu.
-
Gdy wywołujesz
startActivity(), możesz uwzględnić flagę wIntent, która określa, jak (lub czy) nowa aktywność jest powiązana z bieżącym zadaniem.
Jeśli więc aktywność A uruchamia aktywność B, aktywność B może określić w swoim pliku manifestu, jak jest powiązana z bieżącym zadaniem, a aktywność A może użyć flagi intencji, aby określić, jak aktywność B może być powiązana z bieżącym zadaniem.
Jeśli obie aktywności określają, jak aktywność B jest powiązana z zadaniem, żądanie aktywności A zdefiniowane w intencji ma pierwszeństwo przed żądaniem aktywności B zdefiniowanym w jej pliku manifestu.
Definiowanie trybów uruchamiania za pomocą pliku manifestu
Podczas deklarowania aktywności w pliku manifestu możesz określić, jak aktywność jest powiązana z zadaniem, za pomocą atrybutu launchMode elementu <activity>.
Atrybutowi launchMode możesz przypisać 5 trybów uruchamiania:
"standard"- Tryb domyślny. System tworzy nową instancję aktywności w zadaniu, z którego została uruchomiona, i kieruje do niej intencję. Aktywność może być tworzona wielokrotnie, każda instancja może należeć do różnych zadań, a jedno zadanie może mieć wiele instancji.
"singleTop"- Jeśli instancja aktywności już istnieje na początku bieżącego zadania, system kieruje intencję do tej instancji, wywołując jej metodę
onNewIntent(), zamiast tworzyć nową instancję aktywności. Aktywność jest tworzona wielokrotnie, każda instancja może należeć do różnych zadań, a jedno zadanie może mieć wiele instancji (ale tylko wtedy, gdy aktywność na górze stosu wstecznego nie jest istniejącą instancją aktywności).
Załóżmy na przykład, że stos wsteczny zadania składa się z głównej aktywności A z aktywnościami B, C i D na górze (stos to A-B-C-D, z D na górze). Intencja dociera do aktywności typu D. Jeśli D ma domyślny tryb uruchamiania
"standard", uruchamiana jest nowa instancja klasy, a stos staje się A-B-C-D-D. Jeśli jednak tryb uruchamiania D to"singleTop", istniejąca instancja D otrzymuje intencję przezonNewIntent(), ponieważ znajduje się na górze stosu, a stos pozostaje w stanie A-B-C-D. Jeśli jednak intencja dotyczy aktywności typu B, do stosu zostanie dodana nowa instancja B, nawet jeśli jej tryb uruchamiania to"singleTop"."singleTask"- System tworzy aktywność w głównym katalogu nowego zadania lub lokalizuje aktywność w istniejącym zadaniu o takim samym podobieństwie. Jeśli instancja aktywności już istnieje, system kieruje intencję do istniejącej instancji, wywołując jej metodę
onNewIntent(), zamiast tworzyć nową instancję. Wszystkie inne aktywności nad nią zostaną zniszczone.
"singleInstance"- Zachowanie jest takie samo jak w przypadku
"singleTask", z tą różnicą, że system nie uruchamia żadnych innych aktywności w zadaniu zawierającym instancję. Aktywność jest zawsze jedynym elementem zadania. Wszystkie aktywności rozpoczęte przez tę aktywność otwierają się w osobnym zadaniu.
"singleInstancePerTask"- Aktywność może działać tylko jako aktywność główna zadania, czyli pierwsza aktywność, która utworzyła zadanie. Dlatego w zadaniu może być tylko 1 wystąpienie tej aktywności. W przeciwieństwie do trybu uruchamiania
singleTaskta aktywność może być uruchamiana w wielu instancjach w różnych zadaniach, jeśli ustawiona jest flagaFLAG_ACTIVITY_MULTIPLE_TASKlubFLAG_ACTIVITY_NEW_DOCUMENT.
Na przykład przeglądarka Androida określa singleTask w <activity>, więc jej aktywność nie jest umieszczana w zadaniu aplikacji. Zamiast tego uruchamiane jest nowe zadanie przeglądarki lub na pierwszy plan wysuwa się istniejące zadanie przeglądarki w tle.
Niezależnie od tego, czy aktywność rozpoczyna się w nowym zadaniu, czy w tym samym zadaniu co aktywność, która ją uruchomiła, przycisk Wstecz i gest zawsze przenoszą użytkownika do poprzedniej aktywności. Jeśli jednak uruchomisz aktywność, która określa tryb uruchamiania singleTask, a jej instancja istnieje w zadaniu w tle, całe zadanie zostanie przeniesione na pierwszy plan. W tym momencie stos wsteczny zawiera wszystkie aktywności z zadania przeniesionego na górę stosu. Rysunek 4 przedstawia taki scenariusz.
"singleTask" jest dodawana do stosu wstecznego. Jeśli aktywność jest już częścią zadania w tle z własnym stosem wstecznym, cały ten stos wsteczny również zostanie przeniesiony na górę bieżącego zadania.Więcej informacji o używaniu trybów uruchamiania w pliku manifestu znajdziesz w dokumentacji elementu <activity>.
Definiowanie trybów uruchamiania za pomocą flag intencji
Podczas rozpoczynania aktywności możesz zmodyfikować jej domyślne powiązanie z zadaniem, dodając flagi do intencji dostarczanej do startActivity(). Aby zmienić działanie domyślne, możesz użyć tych flag:
FLAG_ACTIVITY_NEW_TASKSystem uruchamia aktywność w nowym zadaniu. Jeśli zadanie jest już uruchomione dla aktywności, która jest uruchamiana, zadanie to jest przenoszone na pierwszy plan z przywróconym ostatnim stanem, a aktywność otrzymuje nową intencję w
onNewIntent().Daje to taki sam efekt jak wartość
"singleTask"launchModeomówiona w poprzedniej sekcji.FLAG_ACTIVITY_SINGLE_TOPJeśli uruchamiana aktywność jest bieżącą aktywnością na górze stosu wstecznego, istniejące wystąpienie otrzymuje wywołanie
onNewIntent()zamiast tworzenia nowego wystąpienia aktywności.Daje to taki sam efekt jak wartość
"singleTop"launchModeomówiona w poprzedniej sekcji.FLAG_ACTIVITY_CLEAR_TOPJeśli aktywność, która ma zostać uruchomiona, jest już uruchomiona w bieżącym zadaniu, system nie uruchamia jej nowej instancji, ale niszczy wszystkie inne aktywności, które są nad nią. Intencja jest dostarczana do wznowionej instancji aktywności, która znajduje się teraz na górze, za pomocą
onNewIntent().Nie ma wartości atrybutu
launchMode, która powoduje takie zachowanie.FLAG_ACTIVITY_CLEAR_TOPjest najczęściej używany w połączeniu zFLAG_ACTIVITY_NEW_TASK. Użyte razem te flagi lokalizują istniejącą aktywność w innym zadaniu i umieszczają ją w pozycji, w której może odpowiedzieć na intencję.
Obsługa podobieństw
Powiązanie wskazuje, do którego zadania aktywność „preferuje” należeć. Domyślnie wszystkie aktywności z tej samej aplikacji są ze sobą powiązane: „preferują” znajdowanie się w tym samym zadaniu.
Możesz jednak zmienić domyślne podobieństwo aktywności. Działania zdefiniowane w różnych aplikacjach mogą mieć wspólne powiązanie, a działania zdefiniowane w tej samej aplikacji mogą mieć przypisane różne powiązania zadań.
Powinowactwo aktywności możesz zmienić za pomocą atrybutu taskAffinity elementu <activity>.
Atrybut taskAffinity przyjmuje wartość ciągu tekstowego, która musi być inna niż domyślna nazwa pakietu zadeklarowana w elemencie <manifest>, ponieważ system używa tej nazwy do identyfikacji domyślnego podobieństwa zadania dla aplikacji.
Powiązanie jest wykorzystywane w 2 sytuacjach:
gdy intencja, która uruchamia aktywność, zawiera flagę
FLAG_ACTIVITY_NEW_TASK.Domyślnie nowa aktywność jest uruchamiana w ramach zadania aktywności, która wywołała metodę
startActivity(). Jest on umieszczany na tym samym stosie wstecznym co element wywołujący.Jeśli jednak intencja przekazana do
startActivity()zawiera flagęFLAG_ACTIVITY_NEW_TASK, system szuka innego zadania, w którym można umieścić nową aktywność. Często jest to nowe zadanie. Nie musi tak jednak być. Jeśli istnieje zadanie o takim samym podobieństwie jak nowa aktywność, aktywność jest uruchamiana w tym zadaniu. Jeśli nie, rozpoczyna nowe zadanie.Jeśli ta flaga powoduje, że aktywność rozpoczyna nowe zadanie, a użytkownik używa przycisku ekranu głównego lub gestu, aby je opuścić, musi istnieć sposób, aby użytkownik mógł wrócić do zadania. Niektóre encje, takie jak menedżer powiadomień, zawsze rozpoczynają aktywności w ramach zadania zewnętrznego, nigdy w ramach własnego, więc zawsze umieszczają
FLAG_ACTIVITY_NEW_TASKw intencjach przekazywanych dostartActivity().Jeśli podmiot zewnętrzny może wywołać aktywność za pomocą tej flagi, zapewnij użytkownikom niezależny sposób powrotu, np. ikonę programu uruchamiającego z filtra
CATEGORY_LAUNCHERw aktywności głównej zadania. Więcej informacji znajdziesz w artykule Rozpoczynanie zadania.Gdy atrybut
allowTaskReparentingaktywności ma wartość"true".W takim przypadku aktywność może zostać przeniesiona z zadania, w którym się rozpoczyna, do zadania, z którym jest powiązana, gdy to zadanie zostanie przeniesione na pierwszy plan.
Załóżmy na przykład, że aktywność, która raportuje warunki pogodowe w wybranych miastach, jest zdefiniowana jako część aplikacji podróżniczej. Ma takie samo podobieństwo jak inne aktywności w tej samej aplikacji, czyli domyślne podobieństwo aplikacji, i można ją ponownie przypisać za pomocą tego atrybutu.
Gdy jedna z Twoich aktywności uruchamia aktywność reportera pogody, początkowo należy ona do tego samego zadania co Twoja aktywność. Gdy jednak zadanie aplikacji podróżniczej zostanie przeniesione na pierwszy plan, aktywność związana z pogodą zostanie ponownie przypisana do tego zadania i będzie w nim wyświetlana.
Czyszczenie stosu wstecznego
Jeśli użytkownik pozostawi zadanie na dłuższy czas, system usunie z niego wszystkie aktywności z wyjątkiem aktywności głównej. Gdy użytkownik wróci do zadania, przywrócona zostanie tylko aktywność główna. System działa w ten sposób, ponieważ zakłada, że po dłuższym czasie użytkownicy porzucili to, co robili wcześniej, i wracają do zadania, aby rozpocząć coś nowego.
Możesz zmienić to zachowanie, używając niektórych atrybutów aktywności:
alwaysRetainTaskState- Jeśli ten atrybut jest ustawiony na
"true"w głównej aktywności zadania, opisane powyżej działanie domyślne nie występuje. Zadanie zachowuje wszystkie aktywności na stosie nawet po długim czasie. clearTaskOnLaunchGdy ten atrybut jest ustawiony na
"true"w aktywności głównej zadania, zadanie jest czyszczone do aktywności głównej za każdym razem, gdy użytkownik opuści zadanie i do niego wróci. Innymi słowy, jest to przeciwieństwoalwaysRetainTaskState. Użytkownik zawsze wraca do zadania w jego stanie początkowym, nawet jeśli opuścił je tylko na chwilę.finishOnTaskLaunchTen atrybut jest podobny do
clearTaskOnLaunch, ale działa na pojedynczej aktywności, a nie na całym zadaniu. Może też spowodować zakończenie dowolnej aktywności z wyjątkiem aktywności głównej. Gdy jest ustawiona na"true", aktywność pozostaje częścią zadania tylko w bieżącej sesji. Jeśli użytkownik opuści zadanie, a następnie do niego wróci, zadanie nie będzie już widoczne.
Rozpoczynanie zadania
Możesz skonfigurować aktywność jako punkt wejścia zadania, nadając jej filtr intencji z określonym działaniem "android.intent.action.MAIN" i określoną kategorią "android.intent.category.LAUNCHER":
<activity ... >
<intent-filter ... >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...
</activity>
Ten filtr intencji wyświetla ikonę i etykietę aktywności w menu z aplikacjami, umożliwiając użytkownikom uruchomienie aktywności i powrót do utworzonego przez nią zadania.
Ta druga możliwość jest ważna. Użytkownicy muszą mieć możliwość opuszczenia zadania i późniejszego powrotu do niego za pomocą tego programu uruchamiającego aktywność. Z tego powodu używaj tylko 2 trybów uruchamiania, które oznaczają działania jako zawsze inicjujące zadanie, "singleTask" i "singleInstance", gdy działanie ma filtr ACTION_MAIN i CATEGORY_LAUNCHER.
Wyobraź sobie na przykład, co mogłoby się stać, gdyby brakowało filtra: intencja uruchamia aktywność "singleTask", inicjując nowe zadanie, a użytkownik spędza trochę czasu na pracy nad tym zadaniem. Użytkownik używa przycisku lub gestu ekranu głównego. Zadanie zostanie wysłane do tła i nie będzie widoczne. Teraz użytkownik nie ma możliwości powrotu do zadania, ponieważ nie jest ono widoczne w menu z aplikacjami.
Jeśli nie chcesz, aby użytkownik mógł wrócić do aktywności, ustaw atrybut finishOnTaskLaunch elementu <activity> na "true". Więcej informacji znajdziesz w sekcji Czyszczenie stosu wstecznego.
Więcej informacji o tym, jak zadania i aktywności są reprezentowane i zarządzane na ekranie Ostatnie, znajdziesz w sekcji Ekran Ostatnie.