Programowanie urządzeń mobilnych (studia niestacjonarne) Lista 2 Aktywności i zdarzenia Jak już wiemy, pojedyncza aktywność reprezentuje pojedynczy ekran z interfejsem użytkownika. W zdecydowanej większości przypadków, może poza najprostszymi aplikacjami, składają się one z więcej niż jedna aktywności. Jak zatem dodać kolejną aktywność do naszej aplikacji? Zaczynamy od standardowej aplikacji z jedną pusta aktywnością: "Zerknijmy" na chwile do metody oncreate w pliku AktywnoscGlowna.java: Zwróćmy uwagę na wiersz o numerze 11. Znajdziemy tam sformułowanie, w którym stwierdza się, że obowiązującym dla tego pliku interfejsem jest ten zdefiniowany w zasobie
R.layuot.activity_aktywnosc_glowna, który oczywiście możemy znaleźć w drzewie projektu w węźle res->layout->activity_aktywnosc_glowna.xml (patrz poniżej). Jak wynika z powyższego, każda aktywność składa się z dwóch plików: kodu wykonywalnego.java, oraz pliku opisującego interfejs czyli.xml. Informacje o aktywnościach wchodzących w skład projektu zapisywane są w pliku AndroidManifest.xml: W przypadku powyższym wyraźnie zaznaczono, która z aktywności (na chwilę obecną jest tylko jedna), będzie uruchamiana jako pierwsza, czyli będzie aktywnością główną. Nowa aktywność w aplikacji Aby dodać do aplikacji kolejną aktywność można postąpić w dwójnasób. Można samodzielnie dodać nowe pliki odpowiadające za kod wykonywalny oraz wygląd (czyli.java oraz.xml), można również skorzystać z kreatora, który tę procedurę znacznie uprości. Nowa aktywność przy użyciu kreatora Aby dodać nową aktywność do aplikacji wybieramy menu File->New->Activity, a następnie jeden z typów proponowanych aktywności. Dla celów przykładu wystarczy EmptyActivity:
Dla parametrów jak powyżej, po zakończeniu działa kreatora drzewo projektu zawierać będzie nowy plik AktwynoscDruga.java oraz activity_aktywnosc_druga.xml. Warto zwrócić uwagę, na to, iż w pliku manifest, również pojawił się stosowny wpis:
Nowa aktywność samodzielnie "krok po kroku" Bazując na przykładzie poprzednim możemy spróbować dodać jeszcze jedną aktywność do realizowanej aplikacji - w tym przypadku dodaną samodzielnie - nie w oparciu o kreatora. Najprościej rozpocząć od węzła (w menadżerze projektu) app->java->[nazwa aplikacji], gdzie przy użyciu menu kontekstowego (pod prawym klawiszem) wybierając New->Java Class dodać możemy nowy plik z kodem wykonywalnym aktywności: W kroku kolejnym należy utworzyć nowy layout, który będzie graficznym reprezentantem klasy utworzonej powyżej. Możemy to wykonać również przy użyciu menu kontekstowego np. węzła app- >res->layout wybierając New->Layout resource file: Oczywiście nazwa aktywność może być dowolna (używamy tylko małych liter), lecz warto pamiętać o stosowaniu jednolitego nazewnictwa w całym projekcie (łatwiej wtedy o zachowanie porządku). Mamy zatem plik.java oraz.xml. Przypomnieć tutaj warto, iż plik zawierający kod wykonywalny aktywności musi mieć przypisany odpowiadający mu plik.xml, a nowo utworzona klasa takiego nie posiada:
Przechodząc zatem do edycji pliku TrzeciaAktywnosc.java musimy wykonać dwie rzeczy: 1. Określić klasę AktywnoscTrzecia jako klasę dziedziczącą po klasie Activity (w końcu reprezentować ma ona aktywność) 2. Przeładować metodę oncreate(), w której określić, który z "layoutów" (zasobów plikach.xml), będzie odpowiadał za wygląd aktywności: Nie można oczywiście zapomnieć o dodaniu nowo utworzonej aktywności do pliku manifestu: Zdarzenia w aktywnościach Oczywiście w każdej aplikacja pracującej pod kontrolą systemu Android mamy do czynienia z bardzo dużą liczbą równych zdarzeń które możemy obsługiwać z poziomu programu, jednak jednym z podstawowych jest zdarzenie, które odpowiada kliknięciu (dotknięciu) przycisku. W tym celu do aktywności głównej przykładowej aplikacji dodać można przycisk (Button), a nawet dwa, gdyż realizowany w tej części przykład zawiera trze aktywności. Dla czytelności działania aplikacji warto oznaczyć je stosowanym komentarzem:
Warto zwrócić uwagę na identyfikatory (@+id) obu dodanych przycisków (wiersze 17 oraz 28). Domyślne identyfikatory o nazwa button1 lub button2 warto zmienić na własne, wskazujące na funkcje jakie dany przycisk na docelowo realizować (warto stosować jednolite nazewnictwo w projekcie). Oczywiście tak dodane przyciski nie będą reagować, na żadne akcje ze strony użytkownika, gdyż nie podpięto do nich jak dotąd obsługi żadnego zdarzenia. W tym celu dodajmy do definicji przycisku w pliku.xml (w tym przypadku activity_aktywnosc_glowna.xml) wiersz, w którym określlimy nazwę metody, jaka powinna zostać wykonana w przypadku wystąpienia zdarzenia onclick() na rzecz poszczególnych przycisków - patrz wiersz 22 poniżej. Oczywiście czynność tę powtarzamy dla przycisku drugiego. Nietrudno się domyślić, iż zapis zastosowany powyżej nie jest wystarczający - koniecznym jest jeszcze napisanie metod, do których się tam odwołujemy, co oczywiście robimy w pliku AktywnoscGlowna.java. Powyżej zaprezentowano treść tych metod - w obu przypadkach są zasadniczo identyczne, więc wystarczy omówić tylko pierwszą z nich. Metoda jako parametr otrzymuje obiekt klasy View (wiersz
15) - jej parametrem aktualnym w momencie wywołania będzie "kliknięty" przycisk. Wewnątrz metody wykorzystamy metodę startactivity, która korzystając z tzw. intencji (ang. Intent), pozwala uruchomić inną aktywność. Tzw. intencje, to jedne z podstawowych komponentów wchodzących w skład aplikacji dla systemu Android. Jest to podstawowy mechanizm służący do wymiany informacji pomiędzy aktywnościami lub innymi komponentami. Jeśli Android Studio oznaczy np. klase View lub Intent jako nieznaną (domyślnie czerwonym kolorem tekstu) należy zaimportować do pliku.java odpowiedni biblioteki (najlepiej postępować zgodnie z sugestiami Android Studio dostępnymi jako menu kontekstowe dla fragmentu oznaczonego jako nieznany tekst). Przekazywanie wartości między aktywnościami Dla zobrazowania zagadnienia posłużyć się można wcześniej przygotowanym szkieletem aplikacji, składającej się z 3 aktywności, z których pierwsza będzie wywoływała pozostałe. Jak zaprezentowano powyżej aktywność główna składa się z pola edycyjnego typu EditText (@+id/poleedycyjne - wiersz 17), oraz dwóch przycisków typu Button (@+id/buttonoknopierwsze - wiersz 27 oraz @+id/buttonoknodrugie - wiersz 37). Warto zauważyć, że w przypadku obu przycisków jako metodę obsługującą zdarzenie onclick wskazano metodę o nazwie ObslugaPrzyciskow co może, aczkolwiek wcale nie musi oznaczać, że oba przyciski będą realizowały takie same funkcjonalności. Jaki kod zatem zawiera metoda ObslugaPrzyciskow, którą umieszczamy oczywiście w pliku AktywnoscPierwsza.java?
1. Wiersz 19 - zmienna pomocnicza typu napisowego - będzie potrzebna w wierszy kolejnym 2. Wiersz 20 - korzystamy z faktu, iż wiemy, który z elementów interfejsu jest źródłem wywołania metody, gdyż informacja ta zawarta jest w parametrze wywołania metody czyli w obiekcie klasy widok, dzięki temu możemy np. sprawdzić jaki napis był na nim umieszczony 3. Wiersz 21 - sprawdzamy, czy wyizolowany w punkcie poprzednim napis odpowiada przyciskowi pierwszemu czy też drugiemu. Jeśli był to przycisk pierwszy wykonujemy operacje w zakresie od wiersza 23 do 27. 4. Wiersz 23 - nowy, tym razem nie anonimowy (patrz wiersz 31 oraz wcześniejsze przykłady) reprezentant klasy Intent. 5. Wiersz 24 - reprezentant pola edycyjnego umieszczonego na aktywności głównej 6. Wiersz 25 - napis, do którego zostanie wpisany ciąg wprowadzony przez użytkownika do pola edycyjnego. 7. Wiersz 26 - wewnątrz intencji z wiersza 23 umieszczamy wartość przechowywaną w napisie Komunikat i nadajemy mu identyfikator PrzesylanyKomunikat 8. Wiersz 27 - uruchomienie aktywności AktywnoscDruga w oparciu o wcześniej przygotowaną Intencję 9. Wiersz 31 - wywołanie aktywności AktywnoscTrzecia przy użyciu intencji anonimowej. Ostatnim krokiem jest przygotowania aktywności AktywnoscDruga do przetworzenie przekazanych danych. Zakładamy, że wyposażona jest ona w pole typu label, na którym wyświetlony zostanie ciąg znaków wpisany przez użytkownika w aktywności głównej. Kod meto oncreate() w pliku AktywnoscDruga.java ma postać: 1. Wiersz 13 - obiekt o nazwie WyswietlaczKomunikatu, który będzie reprezentantem pola typu TexView zdefiniowanego w pliku.xml
2. Wiersz 14 - tekst wyświetlany przez WyswietlaczKomunikatu zostaje ustawiony w oparciu o wartość identyfikatora o nazwie PrzesłanyKomunikat, kótra zostaje pobrana z obiektu Intent (ustawiona została przed wywołaniem aktywności). Rysowanie po powierzchni aktywności Jeśli zajdzie potrzeba programowego narysowania elementów interfejsu użytkownika, wyświetlanych przez aktywność, można posłużyć się różnymi rozwiązaniami. Jednym z najprostszych jest podmiana obiektu reprezentującego domyślny zasób.xml z definicją wyglądu aktywności na własny, zupełnie inny obiekt klasy View (dziedziczące po niej gwoli ścisłości). Przykład takiego rozwiązania zaprezentowano poniżej: 1. Wiersz 44 - podmiana domyślnego kontekstu graficznego (domyślnie była to activity_aktywnosc_glowna). 2. Wiersz 14 - definicja własnej klasy dziedziczącej po klasie View. 3. Wiersz 17 - jawne wywołanie konstruktora klasy przodka czyli View. 4. Wiersz 20 - przeładowanie metody ondraw() dla bieżącego kontekstu rysowania. 5. Wiersz 21 - wywołanie metody ondraw() na rzecz klasy przodka. 6. Wiersz 23 i 24 - ustalenie parametrów pracy pisaka. 7. Wiersz 37 - wymuszenie odświeżenia okna aktywności.
Zasoby Czym są zasoby? Mocno uogólniając do zasobów można zaliczyć wszytko co nie jest kodem JAVY. Pliki XML odpowiadające za wygląd poszczególnych aktywności też są zasobami. Wszystkie są dostępne w drzewie projektu, w węźle res: Załóżmy, że będziemy chcieli dodać do aplikacji np. grafikę. W tym celu musimy dodać ją do projektu, najlepiej kopiując odpowiednie pliki do folderu [drawable]. W opisywanym przypadku dodano dwa pliki graficzne (warto zwrócić uwagę, że nazwy plików powinny zaczynać się od małej litery): Gdy zasoby są juz dodane do aplikacji, do głównej jej aktywności można dodać np. komponent klasy ImageView, którego atrybut src odpowiada za nazwę zasobu źródłowego, który jest w nim wyświetlany. W efekcie otrzymujemy np.:
Zasoby dźwiękowe Drugim po obrazach rodzajem zasobów wykorzystywanych w aplikacjach na system Android są dźwięki. Warto wspomnieć, że system ten pozwala na "natywne" odtwarzanie chociażby plików MP3. Pliki dźwiękowe mogę być odtwarzane z zasobów zewnętrznych takich jak różne pliki w urządzeniu, lokalizacje sieciowe, mogą być też dołączone do zasobów samej aplikacji. Aby dodać np. plik MP3 należy odnaleźć folder RAW w drzewie projektu w węźle RES. Jeśli folder taki nie został wcześniej stworzony, należy go utworzyć korzystając z menu kontekstowego dla węzła RES (można to samo osiągnąć tworząc stosowny folder z poziomu eksploratora plików). Ostatecznie należy umieścić tam właściwy plik (pliki) MP3:
Do sterowanie odtwarzanym dźwiękiem posłużyć się można w najprostszym przypadku prostymi przyciskami. W prezentowanym przykładzie zastosowano 3 przyciski: start (włącza odtwarzanie), stop (zatrzymuje i przenosi na początek utworu) oraz pauza (zatrzymuje odtwarzanie w trybie pauzy. Kod JAVA realizujący te zadania jest w gruncie rzeczy bardzo prosty:
Najważniejsze elementy powyższego przykładu: wiersz 10 - deklaracja obiektu klasy MediaPlayer o nazwie Odtwarzacz - będzie wykorzystany do odtwarzania pliku dźwiękowego wiersz 15 - utworzenie obiektu Odtwarzacz w oparciu o konstruktor, gdzie jako parametry przekazany zostaje bieżący kontekst aplikacji oraz nazwa zasoby zawierającego dźwięk wiersz 19 - metoda start() rozpoczyna odtwarzanie zasobu od początku lub od miejsca gdzie wykonano metodę pause(). wiersz 23 i 24 - zatrzymania odtwarzania zasobu w trybie pauzy, a następie przesunięcie wskaźnika odtwarzania na pozycję 0 sekund (na początek utworu) wiersz 28 - metoda pauza Zadanie 1 (10 pkt) Przygotuj aplikację dla Android, w której zaprezentujesz metody klasy Canvas (oczywiście przykłady nie mogą się ograniczać do podstawowych wielokątów - są przecież wypełnienia, teksty itp). Każdy z przykładów ma mieć własną aktywność, która powinna pozwolić ustalić użytkownikowi parametry rysowania danego obiektu, np. wymiary i kolor wypełnienia prostokąta. Ostateczne rysowanie
przykładów powinno być realizowane przez jedną aktywność, która będzie sterowana przez parametry uruchomieniowe ustalane przez aktywności z poszczególnymi przykładami. Zadanie 1 (20 pkt) Przygotuj aplikację dla Android, która będzie realizować funkcjonalności popularnej gry Memory. Jest to cała rodzina prostych gier komputerowych gdzie graczowi prezentowana jest grupa zakrytych obrazów. Każdy z ukrytych obrazów występuje w grupie 2 razy (tworząc parę). Obrazy rozrzucone są w sposób losowy. Każde kliknięcie w ukryty obraz powoduje jego odsłonięcie. Jeśli w danym momencie nie było innych odsłoniętych obrazów pozostaje ona odsłonięty, aż do momentu odsłonięcia kolejnego. Jeśli kolejny odsłonięty tworzy z poprzednim parę pozostają odsłonięte już na stałe, jeśli nie oba zostają ponownie zasłonięte. Zadaniem gracza jest zapamiętywać i odsłonić wszystkie pary w jak najmniejszej ilości prób. Proszę zaimplementować funkcjonalność realizacji swego rodzaju poziomów gry - po włączeniu aplikacji, każde kolejne wylosowane ułożenie (kolejny poziom gry) udostępnia mniej dopuszczalnych niepoprawnych wskazań par. Gra składać się ma z 16 pól (4x4). Przykładowe rozwiązanie: http://www.naprzerwie.pl/naprzerwie/1,89388,6836485,memory_z_kartami.html