Kurs Android (4)

Autor: Damian Chodorek • Opublikowany: 8 lutego 2015 • Ostatnia aktualizacja: 22 lutego 2015 • Kategoria: android, kursy

Aktywności i cykl życia aplikacji. Podstawy UI.

Wiesz jak utworzyć prosty projekt Androida w Eclipse oraz znasz jego strukturę. Czas na trochę praktycznych ćwiczeń. W tej lekcji zrozumiesz czym jest podstawowa jednostka aplikacji – aktywność oraz czym jest i jak wygląda cykl życia aplikacji

Aktywność (Activity)

Aplikacje składają się z wielu komponentów. Nie wszystkie muszą być wykorzystane w każdej aplikacji naraz. Możemy wybierać tylko te, które są nam potrzebne. Jednym z takich komponentów jest aktywność. To komponent, który odpowiada za dostarczenie aplikacji interfejsu graficznego.

Innymi słowy bez aktywności aplikacja nie ma swojego okna. Typowo aplikacja składa się z wielu aktywności (różnych okien), które są ze sobą luźno powiązane. Jedna z nich jest wyróżniona jako ta, która ma zostać uruchomiona na początku, kiedy użytkownik włączy aplikację.

Aktywności należy sobie wyobrażać jak karty (takie do gry, np. w pokera). Jedna aktywność to jedna karta, która jest na wierzchu. Użytkownik ją widzi i może z niej korzystać. Jeżeli ta aktywność stworzy nową aktywność, to nowa jest kładziona na wierzch, a stara znajdzie się pod nią.

Jeżeli użytkownik zamknie aktywność, np. poprzez wciśnięcie przycisku wstecz, to karta z wierzchu zostanie zdjęta (i wyrzucona), a użytkownik zobaczy tę kartę (aktywność), która była pod nią.

Każda aktywność, która znajduje się pod spodem nie jest niszczona, ale zatrzymana i gotowa do wznowienia. Aktywności mogą więc przejść pod spód na rzecz innych lub zostać całkowicie zdjęte ze stosu (zniszczone).

Przykładowo jedną aktywność może stanowić główne okno aplikacji, a inną aktywność okno z ustawieniami. Każda aktywność dostarcza nowego ekranu logicznej jednostce programu.

Aktywności w praktyce

Stwórz nowy projekt o nazwie com.damianchodorek.kurs.android4. Podczas tworzenia ustaw w kreatorze nazwę aktywności głównej na MainActivity (czyli zostaw domyślną nazwę).

W momencie tworzenia projektu, domyślnie została stworzona aktywność główna. Ta operacja wymaga trzech rzeczy:

1. Stworzenia odpowiedniej klasy w Javie. Musi ona dziedziczyć po jakiejś klasie reprezentującej aktywność, np. Activity.

2. Stworzenia layoutu dla tej aktywności (graficznego wyglądu), który jest w postaci pliku XML.

3. Zdefiniowania aktywności w pliku AndroidManifest.xml oraz oznaczenia jej jako aktywność główna, która powinna być uruchomiona zaraz po włączeniu programu.

Skoro w pliku XML zdefiniowany jest UI, to musi być sposób, aby kod Java mógł się z nim komunikować. Po co? Żeby przykładowo zrobić coś, kiedy użytkownik wciśnie przycisk. Ten temat poruszę innym razem, ponieważ czeka nas coś ważniejszego do zrozumienia.

Cykl życia aplikacji

Każda aktywność posiada zestaw metod, które są wywoływane przez system operacyjny w różnych momentach życia aplikacji. Przykładowo podczas uruchamiania lub zamykania jej, kiedy użytkownik zmieni orientację ekranu, albo kiedy aktywność stanie się nieaktywna (inna aktywność zostanie włączona i będzie na wierzchu stosu). Po co? Daje to programistom możliwość zareagowania na te zmiany.

Dzięki temu możemy posprzątać po naszej aplikacji, przykładowo zamknąć otwarte połączenia.

Poniższy schemat doskonale pokazuje w którym momencie dana metoda jest wywoływana.

Warto zaznaczyć, że system może zabić nieaktywne aktywności w dowolnym momencie, jeżeli uzna iż potrzebuje więcej zasobów. Wtedy także są uruchamiane odpowiednie metody cyklu życia. Wszystko to widać na schemacie.

Teraz zaimplementujemy metody cyklu życia tak, żeby ich wywołania powodowały odpowiedni wpis w konsoli. Dzięki temu zobaczysz, w którym momencie i w jakiej kolejności wywoływana jest dana metoda.

Uzupełnij plik MainActivity.java tak jak poniżej.


import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onCreate()");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onPause()");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onStart()");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onRestart()");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onResume()");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onStop()");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("com.damianchodorek.kurs.android4", "uruchomiono onStop()");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

Uruchom aplikację. Obróć ekran. Wyjdź z niej wciskając przycisk home lub wstecz. Powróć do aplikacji. Sprawdź jakie metody są wykonywane w trakcie. Nie musisz ich wszystkich obsługiwać przy każdej aplikacji, ale warto mieć świadomość, że są dostępne i jak działają.

Gdzie sprawdzić komunikaty, które zdefiniowaliśmy? W LogCat – zakładce, która jest pod obszarem z kodem.

Jeżeli nie masz tego elementu, który zaznaczyłem na czerwono, kliknij zielony plusik i uzupełnij pola:

  • Filter name: com.damianchodorek.kurs.android4,
  • by Log Tag: com.damianchodorek.kurs.android4.

W ten sposób utworzysz filtr, który po zaznaczeniu będzie pokazywał te komunikaty, które zgadzają się z odpowiednim tagiem. Tag zdefiniowaliśmy przy pomocy Log.d("com.damianchodorek.kurs.android4","uruchomiono onStop()");. Pierwszy argument to właśnie tag, drugi to komunikat.

Wygląd okna a plik XML

W pliku activity_main.xml zdefiniowany jest cały wygląd aplikacji. Na tworzeniu UI skupię się w późniejszych lekcjach (ponieważ są ważniejsze tematy do omówienia), ale teraz wyjaśnię mniej więcej jak to działa.

Każdy plik z interfejsem graficznym aktywności jest XML’owy, a więc musi spełniać jego założenia. Przede wszystkim musi mieć korzeń, czyli najbardziej nadrzędny element. Powinien nim być jakiś wrapper. Przykładowo:

  • LinearLayout – to wrapper, w którym dzieci są umieszczone liniowo, to znaczy obok siebie lub jeden pod drugim (w zależności jak zdefiniujemy),
  • RelativeLayout – pozwala ustawić dzieci względem siebie, np. dziecko A będzie po prawej od dziecka B, a B będzie nad dzieckiem C.

Po wybraniu wrappera, który najbardziej odpowiada naszym potrzebom, należy umieścić w nim dzieci. Mamy do wyboru całą masę elementów, które odpowiadają za: grafiki, przyciski, pola tekstowe, pola do wpisywania tekstu itp. W korzeniu możemy umieszczać także inne wrappery.

Wszystkie wspomniane elementy to węzły XML’owe, a ich atrybuty określają różne własności takie jak wysokość, szerokość, kolor tła, kolor tekstu, marginesy, paddingi itp.

Domyślny plik activity_main.xml, który został wygenerowany przez Eclipse, wygląda u mnie tak:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.com.damianchodorek.kurs.android4.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>

Rodzicem jest RelativeLayout, który już omówiłem, a dzieckiem TextView, który jest polem tekstowym. Zwróć uwagę, że wszelkie atrybuty znajdują się w przestrzeni nazw android, stąd zapis w stylu android:paddingBottom.

W androidzie wymiarów nie podaje się w px, ale najczęściej w dp, które są skalowane tak żeby elementy wyglądały dobrze na różnych ekranach.

Dlaczego jest android:paddingBottom="@dimen/activity_vertical_margin", a nie android:paddingBottom="20dp"? W androidzie różne wartości stałe definiuje się w oddzielnych plikach i wykorzystuje się odniesienia do nich, np. @dimen/activity_vertical_margin oznacza, żeby pobrać wartość typu dimen o nazwie activity_vertical_margin, która została zdefiniowana w innym pliku (jest on w folderze values, zgodnie z opisem na poprzedniej lekcji).

Poniżej znajduje się rysunek, w którym przedstawiłem zależność pomiędzy plikiem XML, a faktycznym wyglądem okna.

W activity_main.xml nie zdefiniowano paska nawigacji, który posiada nasza aplikacja (znajduje się na samej górze). Jest to odrębna część interfejsu i jego definicja znajduje się w pliku res/menu/main.xml. Nie posiada definicji wyglądu (kolorów, układu, itd.), ponieważ przypisano mu standardowy szablon Androidowy. Zdefiniowano jedynie elementy (items), które będą się znajdować w menu. Pojawią się po wciśnięciu przycisku w prawym górnym rogu aplikacji. Za elementy (w naszym przypadku jest to tylko jeden element) w menu odpowiada linijka znajdująca się we wspomnianym pliku.

<item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>

Oczywiście wygląd paska nawigacji może być przez nas dowolnie modyfikowany.

W tej sekcji chodziło mi jedynie o to, aby ogólnie pokazać Ci jak zbudowana jest aktywność i jak XML’owe definicje przekładają się na wygląd okna, które widzisz po uruchomieniu aplikacji.

Więcej wiedzy

Jeżeli jesteś zainteresowany i nie chcesz czekać na kolejną część kursu, możesz zajrzeć na strony, które przygotowałem.

część 5