Życie aktywności Nawigując przez aplikacje poszczególne
Transkrypt
Życie aktywności Nawigując przez aplikacje poszczególne
Życie aktywności Nawigując przez aplikacje poszczególne Aktywności przechodzą pomiędzy stanami. Dla przykładu gdy aktywność uruchamia się po raz pierwszy najpierw znajduje się w tle systemu gdzie otrzymuje focus. W czasie działania system wywołuje serie metod związanych z cyklem życia aktywności, w zależności od działań użytkownika uruchamiane są różne stany aplikacji. Tworząc aplikacje androidową mamy możliwość określenia zachowania aktywności podczas przechodzenia pomiędzy różnymi stanami. Tworząc aktywności: W zależności od skomplikowania aktywności nie konieczne jest implementowanie wszystkich metod z cyklu życiowego. Ważne jest jednak aby wiedzieć jak poszczególne działają i jak się je implementuje aby zapewnić odpowiednie zachowywanie programu. Tworząc aktywności należy pilnować aby: • • • • Nie zawiesza się gdy do użytkownika ktoś dzwoni albo użytkownik zmienia aplikacje w trakcie korzystania z naszego programu Nie zużywa zasobów kiedy nie jest używany Nie traci informacji przy opuszczeniu aplikacji przez użytkownika i jest w stanie powrócić do tego samego punktu po powrocie do aplikacji Nie zawiesza się i nie traci danych podczas zmiany orientacji. Aktywność przez dłuższy okres czasu występować może tylko w 3 z tych stanów: • • • Resumed (‘running’) Aktywność działa na głównym ekranie, użytkownik może wchodzić w interakcje z programem Paused Aplikacja jest częściowo zasłonięta inna aktywnością – inna aktywność jest półprzeźroczysta albo nie zasłania całego ekranu. Zatrzymana aktywność nie otrzymuje żadnych inputów i nie przetwarza żadnego kodu. Stopped Aktywnośc jest w ogóle niewidoczna, znajduje się w tle. Aktywność w tym stanie zachowuje wszystkie dane, ale nie może uruchamiać kodu Stany Created oraz Started są przejściowe. Aktywność startowa Kiedy użytkownik wybiera aplikacje z ekranu startowego system uruchamia metodę onCreate() dla aktywności zadeklarowanej jako „launcher” (albo „main”). To która aktywność jest główna definiuje się w manifeście. Główna aktywność musi być zadeklarowana w manifeście wewnątrz <intent-filter> który zawiera akcje MAIN oraz kategorie LAUNCHER: <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> Tworzenie nowej instancji Większość aplikacji zawiera kilka różnych aktywności, kiedy tworzona jest jakakolwiek aktywność wywoływana jest jej metoda onCreate(). Metoda onCreate() powinna uruchomić logikę która powinna wydarzyć się tylko raz na całe życie aktywności na przykład interfejs użytkownika. Poniższy kod przedstawia metodę onCreate() tworzącą podstawowy setup aktywności, taki jak deklarowanie interfejsu w pliku XML, definiowanie zmiennych i konfigurowanie interfejsu. TextView mTextView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); mTextView = (TextView) findViewById(R.id.text_message); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { ActionBar actionBar = getActionBar(); actionBar.setHomeButtonEnabled(false); } } Po uruchomieniu onCreate() system uruchamia metodę onStart() a następnie onResume(). Aktywność nigdy nie przebywa w stanie Created oraz Started. Teoretycznie aktywność staje się widoczna dla użytkownika kiedy wywołana jest metoda onStart() ale onResume() uruchamia bardzo szybko i zostaje już w tym stanie do czasu zmiany przez użytkownika. Niszczenie Aktywności Ostatnim wywołaniem metody jest onDestroy(). System wywołuje tą metodę jako ostateczny sygnał na to, że instancja aktywności jest usuwana z pamięci systemu. Większość aplikacji nie musi implementować metody onDestroy() ponieważ duża część czyszczenia powinna odbywać się w klasach onPause() oraz onStop(). Jednak gdy aktywność zawiera w sobie wątki działające w tle, utworzone w onCreate(), albo zasoby wykorzystywane przez całą aplikację które mogą doprowasdzić do problemów z pamięcią jeśli nie są zamykane poprawnie wówczas należy wyczyścić je ręcznie podczas onDestroy(); @Override public void onDestroy() { super.onDestroy(); android.os.Debug.stopMethodTracing(); } Pausing/Resuming Podczas normalnego działania główna aktywność jest czasami zasłaniana innym komponentem wizualnym który doprowadza do przejścia aktywności do stanu pause. W momencie kiedy aplikacja jest całkowicie niewidoczna przechodzi ona w stan Stop. W momencie przejścia w stan pauzy aplikacja uruchamia metodę onPause() aktywności która została zatrzymana. Metoda ta pozwala zatrzymać działające czynności które nie powinny działać przy zatrzymanym programie (np. film, muzyka itd.) oraz zachować informacje w przypadku opuszczenia aplikacji. W razie powrotu do aplikacji, system wzywa metodę onResume(). Kiedy system uruchamia metodę onPause() oznacza to ze aplikacja nadal jest widoczna, ale istnieje duża szansa, że niedługo aktywność przejdzie w stan Stopped ponieważ użytkownik opuści tą aktywność. Dlatego, zazwyczaj w onPause() powinno się: Zatrzymywać animacje oraz akcje które wymagają CPU Zapisać niezapisane zmiany jeżeli mogą być one potrzebne użytkownikowi później (np. szkic emaila) Zwolnić zasoby które mogą zużywać baterię w czasie zatrzymania aplikacji, kiedy użytkownik ich nie potrzebuje. Dla przykładu: Aplikacja korzysta z kamery, pauza jest dobrym momentem aby przestać jej używać: @Override public void onPause() { super.onPause(); if (mCamera != null) { mCamera.release() mCamera = null; } } Powinno unikać się wykonywania ciężkich operacji w onPause() (np. zapisywania informacji do bazy danych) chyba, że specyfika aplikacji tego wymaga (np. zapisanie wspomnianego już zarysu emaila). Tego typu operacje zazwyczaj powinny odbywać się w onStop(). Resume Przechodząc z onPause do onResume musimy uruchamiać rzeczy które wyrzuciliśmy w onPause, musimy pamiętać, że onPause startuje także podczas pierwszego uruchomienia aplikacji. @Override public void onResume() { super.onResume(); if (mCamera == null) { initializeCamera(); } } Zatrzymywanie i restartowanie aktywności Kiedy aplikacja jest stopowana/restartowana: Użytkownik otwiera inną aplikacje. Dotychczas działająca aplikacja jest zatrzymywana. Jeżeli wróci do tej aplikacji później, jest ona restartowana. Użytkownik wykonuje operację w aplikacji która zaczyna nową aktywność. Obecna aktywność jest zatrzymywana a nowa tworzona. Jeśli użytkownik wciśnie wstecz, wówczas pierwotna aktywność jest restartowana. Do użytkownika ktoś dzwoni. Zatrzymywanie aktywności: Kiedy aplikacja uruchamia metodę onStop() oznacza to, że nie jest już widoczna i powinna usunąć większość zasobów które nie są potrzebne gdy użytkownik jej nie używa. Przykład onStop który zapisuje dane z notesu do bazy danych @Override protected void onStop() { super.onStop(); ContentValues values = new ContentValues(); values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText()); values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle()); getContentResolver().update(mUri, values, null, null);} Restartowanie aktywności Metoda onStart() uruchamia się zawsze gdy aktywność staje się widoczna. Natomiast metoda onRestart() tylko gdy aktywność uruchamia się po stanie stop. Umożliwia to przeprowadzenie specjalnych zadań odtwarzających aplikację do poprzedniego stanu. Najczęściej jednak re-inicjalizację aplikacji przeprowadza się w onStart(). Odtwarzanie aplikacji Aktywność jest niszczona i odtwarzana zawsze gdy obracamy ekran! System domyślnie zapisuje informacje o wszystkich widokach w layoucie. Dlatego podczas zmiany orientacji po zniszczeniu aktywności, stan layoutu jest odbudowany do poprzedniego stanu bez potrzeby kodowania dodatkowej obsługi. Zapisywanie stanu aktywności Zatrzymując aktywność system wywołuje onSaveInstanceState() dzięki którym aktywność może zapisać swój stan za pomocą kolekcji parę klucz-wartość. Domyślnie metoda zapisuje informacje na temat stanu hierarchii widoków takich jak np. tekst w EditText albo pozycja scrolla w ListView. Aby zapisać dodatkowe informacje musimy zaimplementować onSaveInstanceState() i dodać party klucz-wartość : static final String STATE_SCORE = "playerScore"; static final String STATE_LEVEL = "playerLevel" @Override public void onSaveInstanceState(Bundle savedInstanceState) { savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); super.onSaveInstanceState(savedInstanceState); } Przywracanie stanu aktywności W momencie przywracania aplikacji po jej zniszczeniu możliwe jest odtworzenie stanu poprzedniego. Metody onCreate() oraz onRestoreInstanceState() otrzymują tą samą paczke (bundle) która zawiera informacje o stanie aktywności. Ponieważ metoda onCreate() jest uruchamiana kiedy system tworzy nowa instancje aktywności, bądź odtwarza poprzednią – należy sprawdzać, czy stan naszej paczki nie jest nullem przed próbą dostępu do niej. Jeśli jest to null wówczas oznacza to, że system tworzy nową instancje aktywności zamiast przywracania zniszczonej. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { //Zainicjalizuj z domyślnymi wartościami } } W przeciwieństwie do onCreate() metoda onRestoreInstanceState() uruchamia się po onStart() i uruchamia się tylko gdy system ma stan do odtworzenia, w związku z czym nie trzeba sprawdzać czy Bundle jest nullem. public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); }