Aktywności w Androidzie
Wszystkie programy działające pod kontrolą systemu Android składają się z wielu różnych komponentów, które poskładane w jedną całość tworzą znaną przeciętnemu użytkownikowi aplikację. Jednym z takich komponentów są tak zwane aktywności, które wykorzystywane są do interakcji z użytkownikiem. Aktywności tworzą pojedyncze okna w aplikacji oraz odpowiadają za ich uruchomienie. W prostych projektach, każda aktywność odpowiada za jedno okno, w tych nieco bardziej zaawansowanych wykorzystujących na przykład mechanizm fragmentów, może się zdarzyć tak, że w ramach jednej aktywności (okna aplikacji) ujrzymy kilka różnych layoutów co mylnie może zostać odebrane za kilka różnych okien. Ale po kolei…
Aktywność, co to takiego?
Z poprzedniego akapitu, możemy wywnioskować, że aktywność (ang. activity) to jeden z komponentów systemu Android odpowiedzialny za interakcję z użytkownikiem. Na tym w zasadzie można było by zakończyć rozważania w tym punkcie, ale pewnie 99% z was dalej nie wie o co chodzi. Posłużmy się więc krótkim przykładem. W artykule o tworzeniu pierwszej aplikacji w Android Studio, po utworzeniu nowego projektu (aplikacji typu „Hello world”) IDE samoczynnie wygenerowało nam taki oto kod:
package com.example.lukasz.mojapierwszaaplikacja; import android.app.Activity; import android.os.Bundle; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
Znajduje się on w katalogu app/Java/android.mojapierwszaaplikacja w pliku MainActivity.java. Jak wskazuje sama nazwa, plik ten odpowiedzialny jest za kod „głównej aktywności” – cokolwiek to znaczy. Chodzi tutaj o to, że użytkownik po zainstalowaniu tego programu na swoim telefonie i uruchomieniu go ujrzy na pierwszym ekranie wszystko to co zostało wygenerowane w przeładowanej metodzie onCreate()
klasy MainActivity
rozszerzającej klasę Activity
. Brzmi strasznie, ale nie ma się co obawiać. Chodzi tutaj o to, że korzystając z wbudowanego w system Android komponentu Activity
przeładowujemy metodę onCreate()
gdzie za pomocą odpowiedniej funkcji czyli setContentView(),
ładujemy wcześniej przygotowany plik xml z layoutem. Nic trudnego.
Teraz system Android po uruchomieniu aplikacji wie, że główną aktywnością jest aktywność MainActivity
(podawaliśmy tą informację w kreatorze, podczas tworzenia projektu) oraz dzięki przeładowaniu metody onCreate()
, wie jaki layout ma wyświetlić. Innymi słowami, uruchamia okno, które nazywa się MainActivity. Dalej w tym właśnie oknie odbywa się cała interakcja z użytkownikiem (obsługiwane są np. różne zdarzenia jak choćby onClick
– zdarzenie kliknięcia w jakiś element, przykładowo button).
Mam nadzieję, że się trochę rozjaśniło.
Cykl życia aktywności
Jak wiecie, aplikacja mobilna może składać się z wielu aktywności (okien). Kluczowe więc jest pytanie co dzieje się w momencie, w którym przechodzimy z jednej aktywności do drugiej? Jest to temat na tyle interesujący, że sięgnę w tym momencie do dokumentacji Androida skąd pozwolę sobie zaczerpnąć oto taką grafikę, przedstawiającą tzw. cykl życia aktywności:
O co tutaj chodzi? Zacznijmy więc od początku czyli samej góry. Pierwszym etapem cyklu życia aktywności jest jej uruchomienie innymi słowy system Android po uruchomieniu przez użytkownika aplikacji przechodzi do głównej aktywności i ją uruchamia (w ten sposób uruchamiana jest pierwsza – główna aktywność w aplikacji). Następnie czyli już po uruchomieniu aktywności w systemie zachodzą zdarzenia takie jak onCreate()
, onStart()
, onResume()
(dokładnie w takiej kolejności). Dzięki przeładowaniu odpowiednich metod mamy tutaj wpływ na to jak zachowa się nasz program. Na przykład, jak zrobiliśmy to poprzednio możemy, przeładować metodę onCreate()
gdzie definiujemy plik xml z layoutem:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }
Kolejnym etapem jest moment, w którym aktywność jest po prostu uruchomiona. Teraz jest czas na obsługę całej interakcji z użytkownikiem, zdarzeń typu onClick
itd..
Następnie dochodzimy do najciekawszego fragmentu cyklu, kiedy to mamy trzy możliwości zachowania:
- Inna aktywność innymi działaniami (np. poprzez wciśnięcie przez użytkownika przycisku) wychodzi na pierwszy plan,
- Aktywność (obecna) nie będzie już dłużej widoczna,
- Aktywność (obecna) została zakończona, bądź system ją skasował.
Chodzi teraz o to, że gdy dojdzie do realizacji zachowania na przykład z punktu pierwszego: czyli mamy jakieś tam okno (aktywność) z przyciskiem (wygenerowanym w danym layoucie), który uruchamia inną aktywność po kliknięciu w niego. Kiedy użytkownik klika w ten przycisk (w tym momencie na obecnej aktywności zachodzi zdarzenie onPause()
) i uruchamia nowego okno. Teraz mamy już zupełnie inną aktywność na pierwszym planie. Gdy w tym momencie klikniemy przycisk „wstecz” z dolnego menu Androida to wrócimy do poprzedniej aktywności ale uwaga (!), nasz kod z przeładowanej metody onCreate()
nie zostanie wykonany! Jak widać na powyższym obrazku, wracamy w tym wypadku tylko do momentu w którym wykonywana jest metoda onResume()
.
Przeanalizujmy teraz zachowanie z punktu drugiego. Na początek zastanówmy się kiedy takie zdarzenie może zajść? No na przykład wtedy kiedy użytkownik kliknie przycisk „Home” lub tyle razy przycisk „wstecz”, że spowoduje tym sposobem wyjście z aplikacji (np. po włączeniu aplikacji, będąc w głównym oknie wystarczy tylko raz kliknąć przycisk „wstecz” co spowoduje przejście z powrotem menu głównego, bądź aktywności z innej aplikacji). Co wtedy się stanie?
Po kliknięciu przycisku „Home” zostaną wywołane następujące zdarzenia: onPause()
oraz onStop()
(dokładnie w takiej kolejności). Teraz kiedy użytkownik wróci do aplikacji zostanie wywołana metoda onRestart()
, onStart(),
onResume()
(również w takiej kolejności). Uwaga: Może się zdarzyć, że system wcześniej „zabije” naszą aplikację w tle bo na przykład braknie zasobów (choćby pamięci RAM) dlatego bezpieczniej jest wykonać ważne funkcje (np. zapisanie danych) w metodzie onStop()
, a jeszcze bezpieczniej w metodzie onPause()
– każdy musi tutaj indywidualnie zdecydować co chce zrobić.
Teraz zastanówmy się co się stanie kiedy wciśnięcie przycisku „wstecz” spowoduje wyjście z aplikacji (zdarzenie z punktu trzeciego). Zostaną wywołane wtedy następujące metody: onPause()
, onStop()
, onDestroy()
. Jak łatwo wyczytać z powyższego obrazka, w tym przypadku kiedy użytkownik wróci do aplikacji zostanie uruchomione znowu wszystko od początku (dla głównej aktywności) czyli metody onCreate()
, onStart()
, onResume()
.
Podsumowując, nieważne co się stanie zawsze przy powrocie do aktywności jest wywoływana metoda onResume()
jeśli więc musimy przywrócić jakieś ważne dane (np. sms’a wpisywanego przez 30 minut) to możemy to najbezpieczniej zrobić właśnie tutaj (oczywiście o ile wcześniej zapisaliśmy je np. w metodzie onPause()
).
Jeśli chcielibyście „na żywo” zobaczyć jak to wszystko wygląda to wklejcie sobie poniższy kod do waszej aplikacji (oczywiście pamiętajcie o odpowiedniej nazwie package
):
import android.app.Activity; import android.os.Bundle; import android.widget.Toast; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toast.makeText(this, "onCreate()", Toast.LENGTH_LONG).show(); } @Override protected void onRestart() { super.onRestart(); Toast.makeText(this, "onRestart()", Toast.LENGTH_LONG).show(); } @Override protected void onStart() { super.onStart(); Toast.makeText(this, "onStart()", Toast.LENGTH_LONG).show(); } @Override protected void onResume() { super.onResume(); Toast.makeText(this, "onResume()", Toast.LENGTH_LONG).show(); } @Override protected void onPause() { Toast.makeText(this, "onPause()", Toast.LENGTH_LONG).show(); super.onPause(); } @Override protected void onStop() { Toast.makeText(this, "onStop()", Toast.LENGTH_LONG).show(); super.onStop(); } @Override protected void onDestroy() { Toast.makeText(this, "onDestroy()", Toast.LENGTH_LONG).show(); super.onDestroy(); } }
Uruchamianie nowej aktywności
Na koniec warto dowiedzieć się w jaki sposób możemy uruchomić nową aktywność np. w metodzie wywoływanej po wciśnięciu jakiegoś przycisku. Kod odpowiedzialny za tą akcję wygląda następująco:
Intent i = new Intent(this, NowaAktywnosc.class); startActivity(i); finish();
W pierwszej linijce tworzymy nowy obiekt typu Intent
gdzie jako pierwszy parametr podajemy informację o kontekście czyli w naszym przypadku słowo kluczowe this
(informujące o bieżącej aktywności) oraz informację o nowej aktywności czyli drugiej klasie o nazwie np. NowaAktywnosc
(klasa ta rozszerza systemową klasę Activity
).
Dodawanie nowej aktywności do projektu
Aby dodać nową aktywność do naszego projektu wystarczy wybrać odpowiednią opcję w menu kontekstowym:
Teraz wystarczy tylko podać nazwę nowej klasy i gotowe. Aktywność pojawi się automatycznie w projekcie.
Zależy co chcesz zrobić ;) Jest w Androidzie mechanizm, który nazywa się „Fragmenty” nie pisałem o tym jeszcze na blogu, ale generalnie idea tego jest taka, że możesz sobie np. „podmienić” fragment layout w apce. W dokumentacji jest fajny przykład na to: https://developer.android.com/guide/components/fragments.html