W tym wpisie wspomniałem czym są zadania oraz stos i tam napisałem:
Tryby uruchamiania aktywności w Androidzie umożliwiają określenie, w jaki sposób nowa instancja aktywności jest powiązana z bieżącym zadaniem. Czyli możesz zdecydować czy dana aktywność ma się otwierać w nowym zadaniu czy korzystać z bieżącego zadania. Także możesz zdefiniować czy otwierana aktywność ma tworzyć nową instancję czy korzystać z już istniejącej instancji.
Dziś własnie temu tematowi przyjrzymy się dokładniej. Zapraszam 🙂
1. Tryb uruchomienia aktywności za pomocą launchMode w AndroidManifest
Zasadniczo możemy przypisać launchMode bezpośrednio jako atrybut <activity> wewnątrz pliku AndroidManifest.xml:
<activity android:name=".LaunchModeActivity" android:launchMode="standard" android:label="standard launchMode" > </activity>
Dostępne są 4 typy launchMode:
1a. Standard
Jest to domyślna wartość uruchamiana podczas tworzenia aktywności. Typowe zachowanie dla tego trybu to nowa aktywność, która będzie zawsze tworzona, niezależnie od tego ile zostało wysłanych intencji oraz uruchomionych instancji aktywności. Ten rodzaj aktywności zostanie utworzony i umieszczony na szczycie stosu w tym samym zadaniu co aktywność wysyłająca intencję (chyba że obiekt Intent zawiera flagę FLAG_ACTIVITY_NEW_TASK, która uruchamia aktywność w innym zadaniu). Nie ma większego znaczenia czy intencja była wysyłana z tej samej aplikacji czy z obcej.
Powyżej masz diagram, który pokazuje dwie sytuacje udzielone kreską. Po lewej stronie, jeśli użytkownik wywołuje aktywność, a w stosie jej nie ma to jest tworzona nowa instancja aktywności. Po prawej stronie masz sytuacje gdy użytkownik wywołuje ponownie aktywność C. Mimo, ze ona już istnieje w stosie jest i tak tworzona nowa aktywność. Wyobraź sobie, że jeśli wysłano 5 intencji, aby utworzyć wiadomość e-mail, należy uruchomić 5 aktywności. Jeżeli użytkownik chce powrócić do poprzedniej aplikacji, która wysłała intencję to będzie musiał klikać przycisk wstecz aż 5 razy. W rezultacie może istnieć nieograniczona liczba tego rodzaju aktywności uruchomionych w urządzeniu.
1b. SingleTop
Różnica w stosunku do trybu „standardowego” polega na tym, że jeśli instancja aktywności istnieje już na początku stosu to aktywność nie zostanie utworzona tylko zostanie wywołana metoda onNewIntent(). W trybie singleTop musisz obsłużyć przychodzące intencje zarówno w metodzie onCreate() i onNewIntent(). A jeżeli aktywność nie istnieje w stosie to zostanie utworzona. Tryb singleTop działa z tym samym zadaniem, co wywołująca aktywność
Pierwsza sytuacja na diagramu jest prosta, tworzona jest nowa aktywność D ponieważ nie znajduje się na stosie. W drugiej sytuacji wysyłając ponownie intencję do aktywności D, system android nie tworzy nowej instancji, ale korzysta z obecnej. Intencja zostaje obsłużona w metodzie onNewIntent(). Zaś w trzeciej sytuacji, teoretycznie powinno wyglądać tak jak w poprzednim przypadku. A jednak coś się zmieniło. Tutaj jest mały wyjątek, jeśli dana aktywność nie jest na samej górze stosu, a zostaje ona wywołana to tworzona jest nowa instancja aktywności, w przeciwnym wypadku korzysta z obecnej instancji. Dlatego mamy drugą aktywność D na stosie.
Aby zobrazować ten tryb wyobraź sobie aktywność logującą się do serwisu społecznościowego. Aktywność ta wywołuje proces logowania OAuth, system otwiera przeglądarkę. Gdy użytkownik zakończy autoryzację na stronie, zostanie wywołany URL zwrotny i system kieruje intencje do aktywności logującej. Ponieważ tryb uruchamiania aktywności to „singleTop” i instancja aktywności jest na początku stosu to zostanie użyta ponownie i metoda onNewIntent() zostanie wywołana, aby kontynuować zalogowanie do serwisu.
1c. SingleTask
Ustawienie atrybuty launchMode na singleTask oznacza tyle, że dana instancja aktywności może występować tylko raz we wszystkich zadaniach. Jeśli istnieje już jedna instancja aktywności, która nie znajdująca się na początku stosu dowolnego zadania, wówczas wszystkie aktywności powyżej tej instancji zostaną usunięte zgodnie z cyklem życia aktywności, a aktywność startująca wywoła metodę onNewIntent() i stanie się widoczna na ekranie oraz ustawione na początku stosu.
Na diagramie masz pokazaną w drugiej sytuacji, że system niszczy aktywność D, ponieważ nie znajduje się na początku stosu.
Uwaga: W dokumentacji systemu Android jest mowa o tym, że system tworzy aktywność w nowym zadaniu i kieruje do niego intencję. Ma to jednak znaczenie tylko wtedy, gdy aktywność ma tryb uruchamiania jako SingleTask oraz ustawioną wartość UserAffinity na inną niż aplikacja. Na przykład:
<activity android:name=".LaunchMode.singleTaskActivity" android:label="singleTask launchMode" android:launchMode="singleTask" android:taskAffinity=""> </activity>
1d. SingleInstance
Ten tryb jest podobny do SingleTask, z tą różnicą, że aktywność zostanie utworzone w nowym zadaniu. niezależnie od taskAffinity i to zadanie nie może zawierać więcej instancji aktywności. Czyli zadanie będzie zawierać tylko jedną instancję aktywności z trybem uruchamiania jako singleInstance. Jest to bardzo wyspecjalizowany tryb i powinien być używany tylko w aplikacjach, które są w całości realizowane jako jedna aktywność.
2. Tryb uruchomienia aktywności za pomocą flag
Oprócz trybu launchMode możemy uruchamiać aktywności za pomocą flag podczas wywoływania intencji. Możemy wyróżnić następujące flagi:
- FLAG_ACTIVITY_SINGLE_TOP – jest odpowiednikiem launchMode=”singleTop„,
- FLAG_ACTIVITY_NEW_TASK – flaga jest podobna do opisanego powyżej parametru singleTask,
- FLAG_ACTIVITY_CLEAR_TOP – Jeśli uruchamiana aktywność jest już uruchomione w bieżącym zadaniu, to wszystkie aktywności powyżej niej są niszczone, a nowa aktywność jest „tworzona” i znajdzie się na pierwszym planie.
Uwaga!: W przypadku FLAG_ACTIVITY_CLEAR_TOP , jeśli parametr launchMode nie jest zdefiniowany w AndroidManifest lub ustawiony jako „standard” dla aktywności wywołującej, wówczas nowa aktywność wraz z pozostałymi aktywnościami powyżej jej są niszczone. Tak więc, metoda NewIntent() nie jest wywoływana. Jest to niepożądane, w większości przypadków chcemy ponownie wykorzystać aktywność. Aby to osiągnąć, definiujemy parametr launchMode danej aktywności jako singleTop i wywołujemy funkcję startActivity() z flagą FLAG_ACTIVITY_CLEAR_TOP , - FLAG_ACTIVITY_CLEAR_TASK – usuwa wszelkie istniejące zadania, które są powiązane z aktywnością przed utworzeniem jej. To aktywność staje się nowym rootem zadania i stare aktywności są zakończone. Flagę tę można używać tylko w połączeniu z FLAG_ACTIVITY_NEW_TASK.
Wymieniłem tylko flagi, które są najczęściej używane i przydatne. Pamiętaj, że flagi mają pierwszeństwo przed ustawionymi wartościami w AndroidManifest. Więcej informacji na ten temat można znaleźć w Intent. Flagę do intencji możesz dodać w następujący sposób:
Intent i = new Intent(MainActivity.this, SecondActivity.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(i);
3. Określenie nazwy zadania
Zwykle aktywność naszej aplikacji działa w tym samym zadaniu. W razie potrzeby możemy zmienić to zachowanie i określić, która aktywność w jakim zadaniu ma działać. Aby to zrobić, musimy określić nazwę zadania dla danej aktywności w manifeście za pomocą parametru taskAffinity. Jest to wartość, która nie może być taka sama jak nazwa pakietu. Domyślnie zadanie aplikacji nazywa się dokładnie tak jak pakiet aplikacji. Ta opcja jest istotna, jeśli określimy flagę FLAG_ACTIVITY_NEW_TASK lub ustawimy atrybut activity na allowTaskReparenting=”true”.
4. Podsumowanie
Wiesz już czym jest stos, zadania. W jaki sposób uruchomić poszczególne aktywności. Czegoś jeszcze nam brakuje? Musimy jeszcze poruszyć jedno zagadnienie, aby zamknąć ten rozdział, ale tym zajmiemy się w kolejnym wpisie. Bądź czujny! 🙂