Programowanie dla Androida
Aby aktywności mogły się ze sobą komunikować, muszą wykorzystywać mechanizm Intencji (Intent). Intencje zawierają opis operacji i opcjonalnie dane z nią związane. Intencja może wprost wskazać klasę, która ma zostać wywołana (explicite) albo zostawić wybór klasy ART (implicite). Intencje nadawcze (Broadcast Intents) - rozsyłają komunikaty do wszystkich aplikacji w systemie, które zapiszą się na ich nasłuchiwanie (Broadcast Receivers).
Usługi Usługa (Service) to proces, który jest pozbawiony interfejsu użytkownika i może wykonywać zadania w tle. Może zostać uruchomiony i zarządzany przez aktywność. Usługi mogą też wyświetlać wprost powiadomienia.
Manifest aplikacji Jest to plik XML opisujący aplikację. Zawiera informacje o: Aktywnościach, Usługach (Services), Odbiorcach (Brodcast Receivers), Dostawcach danych, Uprawnieniach aplikacji.
Zasoby W pakiecie aplikacji znajdują się też różne zasoby, takie jak: Łańcuchy tekstowe, Grafiki, Czcionki,
Czas życia aplikacji Mimo niezłych specyfikacji technicznych współczesnych telefonów są one nadal uważane za urządzenia o ograniczonych zasobach. Dlatego system zarządza aplikacjami inaczej niż biurkowy system operacyjny. Gdy zaczyna brakować zasobów, procesy są zabijane, a ich zasoby zwalniane. O kolejności zabijania decyduje priorytet procesu.
Czas życia aplikacji Proces pierwszoplanowy Najwyższy priorytet Proces widoczny Proces - usługa Proces w tle Proces pusty Najniższy priorytet
Czas życia aplikacji Stan aplikacji jest wprost zależny od stanu jej aktywności. W trakcie działania systemu wszystkie aktywności są przechowywane na stosie (Activity Stack). Nowa aktywność jest zawsze umieszczana na szczycie stosu. Po zamknięciu aktywności (np. przyciskiem Back ), jest ona zdejmowana ze stosu, a uaktywniana jest ta, która była poprzednio.
Czas życia aplikacji Aktywność uruchamiania Push Pop Stos aktywności Najświeższe Najstarsze Aktywność aktywna Aktywność aktywna poprzednio Aktywność Aktywność najstarsza Zabita Aktywność zamknięta lub użytkownik wrócił do poprzedniej Aktywność zabita aby uwolnić pamięć
Czas życia aplikacji Aktywność może znajdować się w jednym ze stanów: Aktywna - na szczycie stosu, widoczna na ekranie i w interakcji z użytkownikiem, Wstrzymana (Paused) - jest widoczna na ekranie, ale może być częściowo przysłonięta. W każdej chwili jest gotowa do powrotu na wierzch stosu. Zatrzymana - nie jest widoczna, jest stan jest zachowany, ale w stosunku do wstrzymanej jej usunięcie jest bardziej prawdopodobne. Zabita - aktywność została usunięta ze stosu, jej pamięć zwolniona, a ponowne wyświetlenie wymaga inicjalizacji.
Czas życia aplikacji Jeszcze jednym powodem wymuszenia przeładowania aktywności może być zmiana konfiguracji, np. zmiana orientacji ekranu, czcionki systemowej, Aktywność jest wtedy niszczona i inicjalizowana ponownie. Aktywność można skonfigurować aby była niewrażliwa na pewne zmiany.
Narzędzia programistyczne Android Studio - oficjalne środowisko IDE od Google IntelliJIDEA Eclipse Android-IDE Cordova Corona Xamarin CppDroid
Android Studio Dostosowana do potrzeb Androida wersja IntelliJ IDEA Dostępne dla Windows, macos i Linux a Początki od maja 2013 r. Aktualnie wersja 3 od października 2017 r.
Android Studio
Czas życia aktywności Obsługiwany przez metody: oncreate - wywoływana w momencie tworzenia aktywności - ma argument, w którym może otrzymać informacje o poprzednim stanie aktywności onrestart - gdy aktywność ma być wznowiona po wcześniejszym zatrzymaniu przez system onstart - uruchamiana zaraz po oncreate lub onrestart, gdy aktywność ma stać się widoczna
Czas życia aktywności onresume - aktywność jest aktualnie widoczna, a użytkownik może wchodzić z nią w interkację. onpause - gdy aktywność ma być wstrzymana. onstop - aktywność nie jest już widoczna dla użytkownika. ondestroy - aktywność zostanie zabita, z własnej inicjatywy lub przez system
Czas życia aktywności onconfigurationchanged - gdy zajdzie zmiana konfiguracji, która nie spowoduje restartu aktywności. onrestoreinstancestate - wywoływana po metodzie onstart gdy aktywność ma odtworzyć swój zachowany stan onsaveinstancestate - wywoływana przed zabiciem aktywności, gdy aktywność ma zachować swój stan dynamiczny
Czas życia aktywności Przeciążając te metody należy pamiętać, że oprócz dwóch ostatnich należy zawsze wywołać metodę odziedziczoną super.on. Standardowe kontrolki są w stanie same zachować swój stan pomiędzy zmianami stanu aktywności (można to wyłączyć - android:saveenabled= false ) Do przechowania stanu innych elementów można wykorzystać klasę Bundle
Projektowanie UI Urządzenia z Androidem mogą pracować w wielu różnych rozdzielczościach. Urządzenia mogą zmieniać orientację ekranu (pion/ poziom). Wszystkie widoczne elementy dziedziczą po klasie View. Czasami elementy są grupowane w obiekty dziedziczące po klasie ViewGroup.
Projektowanie UI W rozmieszczaniu widoków na ekranie pomagają obiekty typu LayoutManagers, będące specyficznym rodzajem ViewGroup: ContraintLayout - od Androida 7 podstawowy menedżer układu oparty na ograniczeniach LinearLayout - umieszcza elementy w wierszu lub kolumnie TableLayout - umieszcza elementy w macierzy wierszy/kolumn
FrameLayout - blokuje fragment ekranu na najczęściej jeden widok RelativeLayout - elementy rozmieszczane są względem siebie AbsoluteLayout - elementy mają podane bezwzględne współrzędne i rozmiary GridLayout - rozmieszcza elementy na kanwie o cechach macierzy. CoordinatorLayout - od Androida 5 do zarządzania paska na górze aplikacji
Domyślnie źródłowym menedżerem jest ConstraintLayout. Menedżery układu mogą się dowolnie zagnieżdżać, np. GridLayout wewnątrz TableLayout, wewnątrz ContraintLayout. Wszystkie elementy tworzą strukturę drzewa widoków.
Paleta komponentów Pasek narzędzi Atrybuty Drzewo komponentów Projektowany ekran Przełącznik trybu pracy
Design Blueprint
Widok tekstowy
Zdarzenia w Androidzie Użytkownik oraz system generują zdarzenia. Zdarzenia są kolejkowane na zasadzie FIFO. Ze zdarzeniem związane są informacje, które je opisują. Aby obsłużyć zdarzenie, obiekt (najczęściej widok) musi posiadał aktywne nasłuchiwanie (Listener) i odpowiednią do tego metodę.
Zdarzenia LISTENER METODA onclicklistener onclick() onlongclicklistener onlongclick() ontouchlistener ontouch() oncreatecontextmenulistener oncreatecontextmenu() onfocuschangelistener onfocuschange() onkeylistener onkey()
Wielodotyk Android potrafi obsłużyć na raz wiele punktów dotyku Dotyk może składać się w gest Aby przechwycić informacje o dotyku obsługujemy zdarzenie ontouch() Z dotykiem związany jest obiekt MotionEvent, który zawiera informacje o punktach dotyku aktywnych w danym momencie
Gesty Gesty (np. swipe, pinch) można rozpoznawać za pomocą klasy GestureDetectorCompat Informacje o geście musi otrzymywać klasa (niekoniecznie aktywności) posiadająca odpowiednie metody: onfling, ondown, onscroll, onshowpress, onsingletapup, onlongpress W zdarzeniu ontouch trzeba wywołać metodę klasy GestureDetectorCompat Bardziej złożone gesty można definiować samodzielnie
Fragmenty To w pełni niezależny fragment interfejsu użytkownika wraz z logiką, który można umieścić w aktywności Mogą zostać użyte tylko wewnątrz aktywności Na fragment składa się pliku XML opisujący wygląd i klasa opisująca zachowanie Dostępne od wersji 3 Android SDK
Intencje To mechanizm umożliwiający wywoływanie i komunikację pomiędzy aktywnościami Intencja umożliwia wywołanie innej aktywności aplikacji lub aktywności zarejestrowanej w systemie Umożliwiają też komunikację z usługami (Service) i odbiorcami komunikatów (Broadcast receivers)
Intencje explicite Intencje wprost odwołują się do konkretnej aktywności, podając jej dane (nazwę klasy) Najczęściej są używane do wywołania aktywności wewnątrz aplikacji Dane można przekazać przez obiekt klasy Intent, korzystając z metody putextra() Dane są przesyłane jako pary (klucz, wartość)
Intencje explicite Przydatny import Wywołanie intencji
Intencje Aby odczytać przekazane dane, klasa Activity ma własność intent, zwracającą wywołującą ją intencję W klasie Intent jest własność extras, zwracająca obiekt zawierające wszystkie przekazane dane Z niego, za pomocą metod get można odczytać dane
Intencje Aby aktywność można było wywołać, jej opis musi się znaleźć w pliku manifest
Intencje W powyższy sposób można przekazać dane tylko do aktywności wywoływanej Aby przesłać je też w drugą stronę, aktywność musi być wywołana jako pod-aktywność za pomocą metody startactivityforresult( ) Aktywność wywołana musi przeciążyć metodę finish() Aktywność wywołująca musi przeciążyć metodę onactivityresult()
Aktywność nadrzędna Intencje
Aktywność podrzędna Intencje
Intencje implicite Intentcje nie-wprost nie definiują precyzyjnie klasy ale akcję i dane dla niej Np. akcja ACTION_VIEW w połączeniu z adresem URL otworzy aktywność przeglądarki
Filtry intencji Za ich pomocą aktywność może zgłosić systemowi chęć obsługi wybranych akcji Konfiguruje się je w manifeście Aktywność musi też uzyskać odpowiednie uprawnienia dla akcji
Intencje nadawcze Aktywności mogą rozsyłać komunikaty do wszystkich zainstalowanych aplikacji Jeżeli aktywność chce otrzymywać komunikaty, musi się zarejestrować Do odbioru komunikatów musimy stworzyć klasę dziedziczącą po klasie BroadcastReceiver
Intencje nadawcze Są trzy rodzaje intencji nadawczych: zwykłe - po wysłaniu znikają stałe (sticky) - można je odczytać też później dwustronne (ordered) - umożliwiają przesłani danych do nadawcy komunikatu
Wątki Główny wątek aplikacji nie powinien wykonywać intensywnych obliczeniowo zadań Tylko główny wątek powinien wprost wchodzić w interakcję z interfejsem użytkownika Do tworzenie osobnego wątku można wykorzystać klasę AsyncTask Klasa AsyncTask jest klasą generyczną, zależną od 3 typów
Wątki Te 3 typy odpowiadają argumentom metod: doinbackground onprogressupdate onpostexecute Można użyć Void
Wątki Metoda onpreexecute() jest uruchamiana na początku w głównym wątku Główny kod nowego wątku powinien znajdować się w metodzie doinbackground() Metoda onprogressupdate() działa w głównym wątku i ma dostęp do UI Jest uruchamiana w momencie wywołania metody publishprogress() w asynchronicznym wątku Metoda onpostexecute() jest uruchamiana, gdy zakończy się działanie kodu z doinbackground() - działa w głównym wątku
Wątki W ten sposób może działać jeden wątek w tle Kolejne są kolejkowane i uruchamiane po zakończeniu aktywnego wątku Można uruchomić wątki równolegle wywołując metodę executeonexecutor() z klasy AsyncTask O tym, ile wątków może działać równolegle decyduje system w oparciu o liczbę rdzeni procesora
Usługi (Services) Długotrwałe operacje powinny być uruchamiane jako usługi Usługi uruchamiane są poprzez mechanizm intencji i są niezależne od uruchamiającej je aktywności Metody: startservice(), stopservice(), stopself()
Przechowywanie danych Aplikacja na Androidzie może zapisywać i odczytywać pliki Pliki mogą być prywatne dla aplikacji lub dostępne publicznie Można je zapisywać na urządzeniu lub na karcie pamięci
Bazy danych Domyślną bazą danych na Androidzie jest SQLite SQLite został napisany w 2000 r. Przez D. Richard a Hipp a w ramach kontraktu dla US Navy Kod został udostępniony na zasadzie Public Domain Jest to biblioteka napisana w C Realizuje większość funkcji standardu SQL-92 Najpopularniejszy DBMS na świecie www.sqlite.org. http://sqlitebrowser.org
SQLite Nie ma osobnego serwera, kod jest linkowany z aplikacją Metody do obsługi bazy danych są w Androidzie opakowane w klasy
SQLite - Cursor Klasa służąca do przeglądania wyników zapytania: close() - zamyka obiekt getcount() - podaje liczbę wierszy movetofirst() - skacze na początek movetolast() - skacze na koniec movetonext() - przesuwa się do następnego wiersza move( ) - skacze o zadaną liczbę wierszy get<typ>( ) - zwraca wartość z podanej kolumny jako podany typ (wersje getint(), getfloat(), )
SQLite - SQLiteDatabase Klasa zarządza całą bazą danych insert() - wstawia nowy wiersz delete() - usuwa wiersze z tabeli query() - uruchamia zapytanie i zwraca wyniki jako obiekt klasy Cursor exexsql() - umożliwia wywołanie polecenia SQL rawquery() - działa podobnie jak query()
SQLite - SQLiteOpenHelper Klasa zawierająca metody pomagające w zarządzaniu bazą: oncreate() - uruchamiana, gdy baza jest tworzona po raz pierwszy onupgrade() - uruchamiana, gdy aplikacja zawiera nowszą wersję bazy onopen() - uruchamiana w momencie otwarcia połączenia z bazą getreadabledatabase() - otwiera bazę tylko do odczyty getwritabledatabase() - otwiera bazę do odczyty/zapisu close() - zamyka połączenie z bazą
Dostawcy treści Domyślnie baza danych jest prywatne dla aplikacji Aplikację mogą sobie udostępniać dane korzystając z mechanizmu dostawców treści (Content Providers) Przykładem może być aplikacja Kontakty Dane są udostępniane w formie tabelarycznej (jak baza danych) lub jako łącze do pliku
Metody dostawcy treści oncreate() - uruchamiana w momencie inicalizacji query() - zewnętrzna aplikacja wywołuje tę metodę aby uzyskać dane insert() - jak wyżej, tylko wstawiamy nowe dane update() - do uaktualnienia danych delete() - usuwa dane gettype() - zwraca typ przechowywanych danych w formie MIME
Dostawcy treści Dostawca jest identyfikowany w systemie poprzez URI URI może też zawierać parametry danych do pobrania W komunikacji pośredniczy klasa ContentResolver, którą można uzyskać wywołując metodę getcontentresolver() Dostawca musi być zdefiniowany w manifeście - znacznik <provider> zawierający: android:authority - pełne URI dostawcy android:name - nazwa klasy, często taka sama
Storage Access Od Androida 4.4 zaimplementowano bibliotekę Storage Access Umożliwia ona dostęp do kompatybilnych systemów chmurowych, np. Google Drive i Box Mechanizm działa na zasadzie intencji i wywoływania aktywności współpracującej z SA (tzw. Picker)
Uprawnienia aplikacji Do wersji 6 Androida wszystkie uprawnienia były ustawiane w manifeście aplikacji Od wersji 6 uprawnienia są dzielone na zwykłe (zatwierdzane w momencie instalacji) i niebezpieczne (zatwierdzane w czasie działania kodu) Niebezpieczne potwierdza użytkownik w oknie dialogowym
Niebezpieczne uprawnienia GRUPA Kalendarz Kamera Kontakty Lokacja Mikrofon Telefon Czujniki Telefon - wiadomości Przechowywanie danych UPRAWNIENIA odczyt, zapis CAMERA odczyt, zapis, GET_CONTACTS dokładna i przybliżona nagrywanie audio odczyt stanu, połączenie, rejestr połączeń, poczta głosowa, połączenia wychodzące BODY_SENSORS SMS, wyślij, odbierz, czytaj, MMS, WAP_PUSH odczyt i zapis z zewnętrznego źródła
Uprawnienia Aplikacja zawsze powinna sprawdzić, czy otrzymała uprawnienie do danej czynności - metoda checkselfpermission() Po dodaniu na starszym Androidzie uprawnień do manifestu aplikacja uprawnienia będzie miała
Uprawnienia Od Androida 6 aplikacja musi w trakcie działania zapytać się o pozwolenie. Służą do tego metody: requestpermissions() onrequestpermissionresult() Proces ten jest asynchroniczny
Uprawnienia
Teraz aplikacja ma już uprawnienia do ponownej instalacji lub odebrania uprawnień przez użytkownika Uprawnienia
Uprawnienia Aplikacja może uzasadnić swoje żądanie uprawnień korzystając z metody shouldshowrequestpermissionrationale()