JAVA : TELEFONY KOMÓRKOWE I ANDROID 1. WSTĘP

Wielkość: px
Rozpocząć pokaz od strony:

Download "JAVA : TELEFONY KOMÓRKOWE I ANDROID 1. WSTĘP"

Transkrypt

1 JAVA : TELEFONY KOMÓRKOWE I ANDROID 1. WSTĘP Krótko mówiąc, ta książka dotyczy programowania telefonów komórkowych i chociaż w zasadzie nie różni się tak bardzo od pisania programów na zwykłym komputerze, istnieją również znaczne różnice. Po pierwsze, programy są napisane w Javie, więc strona obudowy powinna być na miejscu, ale to, co odróżnia programowanie, to różnice w sprzęcie. Android jest używany jako system operacyjny na różnych urządzeniach, takich jak telefony komórkowe, tablety, smart TV i tak dalej, i chociaż punktem wyjścia dla tej książki jest smartfon, różnią się one również znacznie przy różnych rozmiarach ekranu i innych opcje Co więcej, rozwój rynku telefonów komórkowych jest tak szybki, że pisanie programów dla najnowszych telefonów komórkowych nie jest pewne, że są obsługiwane tylko przez kilka telefonów. Dlatego podczas pisania aplikacji na telefony komórkowe należy wziąć pod uwagę cały szereg nowych czynników. Jako narzędzie programistyczne do końca tej książki będę korzystał z Android Studio, IDE od Google. Dodatek A wyjaśnia, jak pobrać i zainstalować produkt oraz co należy zrobić, aby skonfigurować środowisko programistyczne aplikacji na Androida. W dalszej części chciałbym założyć, że Android Studio jest zainstalowany, a w dalszej części tej sekcji pokażę, jak napisać prostą aplikację, która może konwertować kilometry na mile i odwrotnie, przeliczać mile na kilometry, i to to trochę więcej niż Hello World. Chcę skupić się na tym, co powinieneś zrobić, ale nie tyle na tym, jak to wszystko działa, co chcę odłożyć na później. Zaczynam od otwarcia Android Studio. Czy po raz pierwszy otwierasz program, pojawia się następujące okno: Tutaj klikam górny link Rozpocznij nowy projekt Android Studio, a wynikiem jest następujące okno, w którym muszę wpisać nazwę projektu (tutaj KmMiles) i gdzie w systemie plików projekt powinien zostać utworzony:

2 Podałem także nazwę domeny firmy, która zazwyczaj jest adresem internetowym, a nazwa znajduje się w nazwie pakietu projektu. Po kliknięciu przycisku Dalej pojawi się okno: gdzie wybrać, co to jest dla aplikacji, którą chcesz utworzyć i jaką wersję systemu operacyjnego chcesz obsługiwać. Wybrałem, że aplikacja powinna być Telefon i tablet i że powinien obsługiwać API 22 dla Androida 5.1. Należy pamiętać, że Android Studio pisze, że mogę oczekiwać, że moja aplikacja będzie działać na 62,6 procentach wszystkich urządzeń. Zamiast tego, gdybym wybrał najnowszą wersję, chciałbym wiedzieć, że moja aplikacja może działać na mniej niż 1

3 procent wszystkich urządzeń. W następnym oknie musisz wybrać aktywność telefonu, która odpowiada ogólnemu układowi ekranu i jakie elementy powinny na nim znajdować: W tym przypadku wybrałem opcję Puste działanie, która jest domyślna. W następnym oknie ponownie wybierz nazwę tego działania, które staje się nazwą klasy, i musisz także wybrać nazwę układu. Nie ma specjalnych powodów, aby wybierać inne nazwy niż to, co domyślnie zrobił Android Studio, więc zachowuję te nazwy. Po kliknięciu przycisku Dalej pojawi się okno, w którym Android Studio buduje projekt, a następnie należy kliknąć przycisk Zakończ. Czy po raz pierwszy uruchamiasz program, Android Studio prosi o pobranie dodatkowych plików, co powinieneś zrobić, a po otwarciu okna z kodem programu przez Android Studio może być konieczne kliknięcie kilku linków do pobrania, ale potem projekt został utworzony i gotowy i możesz rozpocząć programowanie

4 Poniżej zrzut ekranu z Android Studio po utworzeniu projektu: Po lewej stronie znajduje się przegląd plików projektu, o których nie chcę wspominać w tym miejscu. W przeciwnym razie istnieją dwie zakładki, gdzie pierwsza pokazuje układ aplikacji, a druga pokazuje klasę Java, która odpowiada klasie głównej w tradycyjnej aplikacji Java. Układ nazywa się activity_main i jest dokumentem XML, który definiuje interfejs użytkownika. Z dokumentem można pracować zarówno w trybie projektowania, w którym można umieszczać komponenty za pomocą myszy, jak i bezpośrednio w kodzie XML. Możesz przełączać się między tymi dwoma trybami, klikając dolne zakładki (Projekt i Tekst). Projekt jest w rzeczywistości kompletną aplikacją, którą można zbudować i przetestować. Aby przetestować program, kliknij zieloną strzałkę po aplikacji na pasku narzędzi. Gdy to zrobisz, pojawi się następujące okno:

5 gdzie wybrać urządzenie, na którym chcesz przetestować program. Za pierwszym razem okno jest puste. Brak podłączonego urządzenia, ale możesz utworzyć urządzenie wirtualne, klikając dolny przycisk. Tutaj najpierw zobaczysz, które urządzenia wirtualne są dostępne. Kiedy tworzyłem projekt, zdecydowałem, że aplikacja musi obsługiwać API 22, więc muszę wybrać urządzenie wirtualne. Wybrałem Nexusa 4, aw następnym oknie będziesz musiał pobrać bieżące urządzenie. Wymaga to niektórych pobrań, ale kiedy tak się dzieje, masz urządzenie wirtualne, jak pokazano w powyższym oknie. Kiedy kliknę OK, Android Studio otworzy emulator (patrz poniżej). Trwa to chwilę, ponieważ musisz pobrać sam emulator, a jego uruchomienie zajmuje dużo czasu, ale z niewielkim kłopotem pojawi się okno, które symuluje telefon i aktywną aplikację. Na razie aplikacja jest trywialna, ponieważ nie robi nic poza pisaniem tekstu w oknie. Teraz rozwinę program z tego, co Android Studio automatycznie wygenerowało, do aplikacji, która otwiera emulator, jak pokazano poniżej, to znaczy aplikacji, w której możesz wprowadzić liczbę, a następnie kliknąć przycisk Konwertuj i w zależności od tego, który przycisk opcji jest zaznaczone, wprowadzona liczba jest interpretowana jako mile lub kilometry, a liczba jest konwertowana na wartość w przeciwnej jednostce. To klasyczny program do konwersji. Jest to oczywiście bardzo prosty program, na który składa się - pole tekstowe - dwa przyciski radiowe - i dwa przyciski ale jest to jednak program, który wykonuje przetwarzanie danych, a nie tylko pokazuje tekst.

6 Aby napisać program, uruchomię w oknie projektu i przeciągnę komponenty z przybornika do drzewa komponentów okna projektu: Projekt pierwotnie miał komponent, który wyświetlał tekst Hello World. Usunąłem ten komponent, a następnie dodałem - LinearLayout, istnieje jakiś menedżer układu - EditText (zwykły tekst), jest pole wejściowe - RadioGroup, która jest pojemnikiem na komponenty - dwa elementy RadioButton - układ liniowy - dwa elementy Button

7 Należy zauważyć, że panel projektu pokazuje, w jaki sposób poszczególne komponenty są zagnieżdżone w hierarchii. Zauważ również, że jeśli wybierzesz komponent za pomocą myszy, po prawej stronie okna pojawi się panel, w którym możesz określić właściwości tego komponentu. Jeśli przejrzysz pliki projektu, zobacz aplikację res wartości, istnieje plik o nazwie strings.xml. Jest to dokument XML, który definiuje ciągi i inne zasoby, które aplikacja może zastosować, i zdefiniowany jest tylko jeden, czyli nazwa programu. Rozszerzyłem plik o 5 nowych definicji, pierwsze 4 to teksty przycisków radiowych i innych przycisków, a ostatnie to kolor tła okna: <resources> <string name="app_name">kmmiles</string> <string name="km">kilometers to miles</string> <string name="ml">miles to kilometers</string> <string name="ok">convert</string> <string name="cl">clear</string> <color name="bgcolor">#f5f5dc</color> </resources> Następnie wyświetlę gotowy XML dla interfejsu użytkownika, który jest generowany automatycznie przez okno projektanta, ale w którym dokonałem pewnych zmian: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" -android:layout_height="match_parent" tools:context="dk.data.torus.kmmiles.mainactivity"> android:background="@color/bgcolor" <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margintop="20dp" android:layout_marginstart="20dp"> <EditText android:id="@+id/edittext1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:inputtype="numbersigned numberdecimal"/> <RadioGroup android:id="@+id/radiogroup1" android:layout_width="match_parent" android:layout_height="match_parent"> <RadioButton android:id="@+id/radiobutton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" android:text="@string/ml" />

8 <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="20dp" android:onclick="onclick"/> <Button android:layout_height="wrap_content" android:onclick="onclick"/> android:layout_width="wrap_content" android:layout_margintop="20dp" </LinearLayout> </RadioGroup> </LinearLayout> </android.support.constraint.constraintlayout> Kiedy widzisz kod, nie możesz oczywiście wiedzieć, że powinien być napisany w ten sposób, ale możesz łatwo zrozumieć kod i znaczenie poszczególnych wierszy. Należy szczególnie zwrócić uwagę na sposób tworzenia identyfikatora dla komponentu (dla widżetu), takiego jak android: id = "@ + id / edittext1" Powinieneś również zwrócić uwagę na to, jak odwoływać się do zasobów (zdefiniowanych w strings.xml) i jako przykład: android: text = "@ string / km" Na koniec zauważ, że dla dwóch przycisków zdefiniowano moduł obsługi zdarzeń. Zasadniczo dokument określa, jakie komponenty powinno mieć okno i jak powinno być rozmieszczone, a ponadto dla każdego widgetu zdefiniowano szereg atrybutów wraz z wartościami odpowiednich właściwości dla obiektów, z których musi się składać gotowy program. Aby wykonać konwersję, dodałem klasę o nazwie Konwerter do katalogu (lub pakietu w panelu projektu) java dk.data.torus.kmmiles: package dk.data.torus.kmmiles;public class Converter private static final double factor = ; public static double tokm(double miles) return miles * factor;

9 public static double toml(double kilometers) return kilometers / factor; Klasa jest oczywiście trywialna i została uwzględniona wyłącznie w celu pokazania, że aplikacja na Androida może zawierać klasy Java w taki sam sposób, jak inne aplikacje Java i że jest to zwykła klasa Java. Tam jest główna klasa MainActivity: package dk.data.torus.kmmiles; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.view; import android.widget.edittext; import android.widget.radiobutton; import android.widget.toast; public class MainActivity extends AppCompatActivity protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); public void onclick(view view) EditText text = (EditText) findviewbyid(r.id.edittext1); if (view.getid() == R.id.button1) text.settext("");

10 else if (view.getid() == R.id.button2) RadioButton ml = (RadioButton) findviewbyid(r.id.radiobutton1); RadioButton km = (RadioButton) findviewbyid(r.id.radiobutton2); if (text.gettext().length() == 0) Toast.makeText(this, "Please enter a valid number", Toast.LENGTH_LONG).show(); return; double value = Double.parseDouble(text.getText().toString()); if (ml.ischecked()) text.settext(string.valueof(converter.tokm(value))) else text.settext(string.valueof(converter.toml(value))); Jak widać, jest to znowu zwykła klasa Java. Oto oncreate () stworzony przez Android Studio, podczas gdy program obsługi zdarzeń powinien zostać napisany. Nie ma wiele do wyjaśnienia na temat kodu, ale powinieneś zauważyć, jak odwoływać się do poszczególnych składników (widżetów).następnie w zasadzie program jest kompletny i można go przetłumaczyć i otworzyć w emulatorze, ale w praktyce należy zrobić więcej, zanim program będzie mógł zostać spakowany i umieszczony do pobrania w sklepie z aplikacjami. Odłożę to na później, ale tutaj kilka słów o tym, co jest potrzebne. Po pierwsze, program musi zostać przetestowany przy różnych rozmiarach ekranu, czyli przy różnych emulatorach. Następnie program musi zostać przetestowany pod kątem projektu fizycznego, co w rzeczywistości jest dość proste. Możesz podłączyć swoje urządzenie (telefon) za pomocą kabla USB. Aby Android Studio mogło zobaczyć urządzenie, musi odblokować telefon jako urządzenie programisty. Możesz dowiedzieć się, jak to zrobić html? utm_source = android-studio a następnie możesz wybrać urządzenie fizyczne po uruchomieniu programu, w taki sam sposób jak w emulatorze, po którym program jest zainstalowany i uruchomiony na telefonie. ĆWICZENIE 1: OBLICZENIA Musisz napisać program przy użyciu tej samej procedury, jak pokazano powyżej. Po otwarciu programu w emulatorze powinieneś wyświetlić okno, jak pokazano poniżej, zawierające następujące widżety: - Układ liniowy - TextView - EditText - ButtonGroup z dwoma widżetami RadioButton

11 - układ liniowy z dwoma widżetami przycisków - TextView - EditText - TextView - EditText - TextView - EditText W górnym polu wejściowym musisz być w stanie wprowadzić cenę jednostkową, podczas gdy w następnym polu musisz podać liczbę jednostek. Po kliknięciu przycisku OK aplikacja musi obliczyć całkowitą cenę bez VAT (w zależności od tego, który przycisk radiowy zostanie naciśnięty), VAT i cenę całkowitą z VAT, a następnie należy zaktualizować trzy dolne pola wprowadzania. Po naciśnięciu przycisku Wyczyść wszystkie pola wprowadzania muszą być puste. Po rozwiązaniu ćwiczenia umieść teksty w pliku strings.xml w taki sam sposób, jak w przykładzie wprowadzającym. Trzy dolne pola wprowadzania powinny w zasadzie być tylko do odczytu. Spróbuj dowiedzieć się, jak to zrobić. 2 Widżety Jeśli weźmiesz przykład wprowadzający, zawiera on 5 elementów sterujących: - pole wprowadzania - kontrolka EditText

12 - dwa przyciski radiowe - Przyciski RadioButton - dwa przyciski - Sterowanie przyciskami W Androidzie są to tak zwane kontrolki dla widżetów, ale powyższe są takie same, jak znane z Swing lub JavaFX. Istnieje wiele takich widżetów, a niektórzy z pierwszych, którzy uczą się pisać aplikacje na Androida, oczywiście uczą się, które i jak z nich korzystać. Nie chcę systematycznie przeglądać różnych składników tej książki, ale ilustruję niektóre z nich za pomocą przykładów, ale w zasadzie są one używane w taki sam sposób, w jaki znasz je z kontrolek w Javie. Rzeczy nazywane są oczywiście czymś innym, a istnieją inne właściwości, które można ustawić, ale zasady są takie same. Widżety są ułożone w rozbudowaną hierarchię klas, w której ogólna klasa podstawowa nazywa się Widok. W tym kontekście dobrze jest znać adres internetowy który jest podstawowym źródłem wielu funkcji Androida. Podobnie jak w przypadku Swing i JavaFX, największym wyzwaniem jest umieszczenie komponentu w oknie, w którym teraz dokładnie chcesz, aby były, ale także, aby okno wyglądało ładnie przy różnych rozmiarach ekranu, ale to jest temat następnej części. Ogólnie rzecz biorąc, Android ma te same widżety, które znasz jako formanty w Swing / JavaFX, ale może są one nazywane czymś innym. Są jednak nowe, których nie ma w Javie, i na przykład chcę pokazać aplikację z dwoma widżetami - Switch, który jest alternatywą dla CheckBox - AnalogClock, har pokazuje zegar (widżet jest teraz przestarzały) Projekt nazywa się TheClock, a jeśli otworzysz aplikację w emulatorze, wynik będzie taki, jak pokazano poniżej. Aplikacja pokazuje zegar analogowy, który liczy się w minutach. Przez całą dobę jest przełącznik (znasz widżet z telefonu), który pokazuje tekst i jest kontaktem, który możesz włączać i wyłączać. Jeśli uruchomisz aplikację, możesz ukryć zegar, klikając element sterujący Przełącz i możesz wyświetlić go ponownie, klikając go. Projekt został utworzony dokładnie w taki sam sposób, jak przykład w rozdziale wprowadzającym, w którym postępowałem zgodnie z tym samym kreatorem, a jedyną różnicą jest to, że wprowadziłem inną nazwę projektu. Następnie usunąłem widget TextView, który dodał Android Studio i zamiast tego dodał LinearLayout i ponownie widżet Switch. AnalogClock nie istnieje w przyborniku (ponieważ jest przestarzały), więc muszę go dodać, wprowadzając kod XML.

13 Kod jest bardzo prosty, a najważniejszy to main_activity.xml, który definiuje interfejs użytkownika: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout schemas.android.com/apk/res/android" xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="dk.data.torus.theclock.mainactivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Switch android:id="@+id/switch1" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="30dp" android:checked="true" android:text="set Clock on/off" android:onclick="onclick"/> <AnalogClock android:id="@+id/analog" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerhorizontal="true" /> </LinearLayout> </android.support.constraint.constraintlayout> Znowu łatwo jest zrozumieć kod, gdy go zobaczysz, i pamiętaj, że Android Studio stworzył najwięcej. Jedyne, co jest trudne do zrozumienia, to atrybuty szerokości i wysokości, ale wyjaśniono to w następnym rozdziale. Zauważ, że obiekt Switch ma moduł obsługi zdarzeń, który musi być zapisany w kodzie Java, a zadanie zmienia widoczność zegara w zależności od stanu kontaktu Switch:

14 package dk.data.torus.theclock; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.*; import android.widget.*; public class MainActivity extends AppCompatActivity protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); public void onclick(view view) Switch sw = (Switch) findviewbyid(r.id.switch1); AnalogClock cl = (AnalogClock) findviewbyid(r.id.analog); if (sw.ischecked()) cl.setvisibility(view.visible); else cl.setvisibility(view.invisible); 2.1 APLIKACJA ZIPCODE Chcę wyjść z tej części na temat widżetów z kolejnym prostym przykładem aplikacji. Musi to być aplikacja, w której możesz wyszukiwać duńskie kody pocztowe, wprowadzając tekst do wyszukania, odpowiednio, kodu pocztowego i nazwy miasta - aplikacja, której użyłem kilka razy jako przykład. W porównaniu z powyższym przykładem aplikacja jest nieco większa, a zatem lepiej odzwierciedla wygląd typowej aplikacji na telefon komórkowy. Jeśli wykonasz aplikację w emulatorze, otrzymasz następujący wynik, w którym Sk szuka nazwy miasta. Wynikiem są wszystkie kody pocztowe, w których nazwa miasta zawiera Sk. Zamiast tego, szukając numeru, otrzymujesz kody pocztowe, w których numer zaczyna się od szukanego tekstu. Tym razem kod wypełnia się trochę więcej i chcę zacząć od pliku zasobów strings.xml: <resources>

15 <string name="app_name">zipcodes</string> <string name="codelabel">code</string> <string name="citylabel">city</string> <string name="clrlabel">clear</string> <string name="seeklabel">search</string> <color name="bgcolor">#f5f5ba</color> </resources> który definiuje teksty interfejsu użytkownika oraz kolor tła. Nie jest to wymagane, aby było to zdefiniowane jako zasoby, ale zaleca się łatwą zmianę programu bez konieczności obchodzenia kodu, a także otwiera się na wersje językowe aplikacji. Interfejs użytkownika został zbudowany w oknie projektanta poprzez pobieranie komponentów z przybornika, a następnie edytowałem kod XML. Trochę się to wypełnia: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout schemas.android.com/apk/res/android" xmlns:app=" xmlns:tools=" android:layout_height="match_parent" tools:context="dk.data.torus.zipcodes.mainactivity"> xmlns:android=" android:layout_width="match_parent" android:background="@color/bgcolor"

16 <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margintop="20dp" android:layout_marginleft="20dp" android:layout_marginright="20dp" android:orientation="vertical"> <TableLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TableRow android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginright="10dp" android:textsize="18dp" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="4" android:inputtype="number" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_marginright="10dp" android:textsize="18dp" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:inputtype="textpersonname"/> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="60dp" android:orientation="horizontal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:layout_margintop="10dp" android:onclick="onclick"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:layout_margintop="10dp" android:onclick="onclick"/>

17 </LinearLayout> </TableRow> </TableLayout> <ListView android:layout_margintop="20dp" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout> </android.support.constraint.constraintlayout> Znowu kod jest wystarczająco łatwy do zrozumienia. Podstawowym układem jest układ liniowy z dwoma elementami ułożonymi pionowo: - Układ tabeli - ListView TableLayout można traktować jak tabelę HTML, w której elementy są uporządkowane w rzędach i kolumnach. W takim przypadku komponent służy do utworzenia formularza z polami wejściowymi i przyciskami. Istnieją trzy wiersze, w których pierwszy ma etykietę (widget TextView) i pole wejściowe (widget EditText). Zwróć uwagę, które atrybuty są zdefiniowane, a zwłaszcza w przypadku tych ostatnich, że możesz wprowadzać tylko liczby całkowite. Następny rząd jest w zasadzie identyczny, a drugi jest nieco inny. Każdy wiersz ma dwie komórki, a pierwsza komórka w ostatnim rzędzie ma pustą etykietę. Druga komórka ma układ liniowy z dwoma przyciskami (widżety przycisków). Zauważ, że oba przyciski mają moduł obsługi zdarzeń, który musi być zdefiniowany w kodzie programu - klasa MainActivity. ListView to widżet, który odpowiada polu listy i jest tymczasowo pusty, ponieważ powinien zostać zainicjowany w kodzie. Jak widać z powyższego, sekcja XML działania może szybko stać się obszerna, ale jeśli piszesz aplikacje na telefony komórkowe, zaleca się (ze względu na rozmiar ekranu), aby okno zawierało tylko kilka widżetów, a jeśli tak, to jest potrzeba wielu, aplikacja powinna zamiast tego korzystać z większej liczby działań, o czym później pokażę przykłady. Z tyłu jest kod Java, gdzie tym razem oprócz MainActivity są dwie inne klasy, które są zwykłymi klasami modelowymi. Chodzi o to, aby pokazać, że aplikacja na Androida składa się z klas w taki sam sposób, jak inne aplikacje, i ponownie, w zasadzie, że pisanie aplikacji mobilnych nie różni się tak bardzo od innych aplikacji na PC. Po pierwsze, chcę dodać do projektu następującą prostą klasę modelu: package dk.data.torus.zipcodes; public class Zipcode private String code; private String city; public Zipcode(String code, String city) this.code = code; this.city = city;

18 public String getcode() return code; public String getcity() return city; public String tostring() return getcode() + " " + getcity(); który reprezentuje kod pocztowy. Następnie dodałem klasowe kody pocztowe, w których kody pocztowe są zdefiniowane jako stałe, i gdzie klasa tworzy niestandardową listę z obiektami Zipcode: package dk.data.torus.zipcodes; import java.util.*; public class Zipcodes private List<Zipcode> list = new ArrayList(); public Zipcodes() for (int i = 0; i < codes.length; ++i) list.add(new Zipcode(codes[i][0], codes[i][1])); public List<Zipcode> search(string code, String city)

19 city = city.tolowercase(); List<Zipcode> lines = new ArrayList(); for (Zipcode z : list) if (z.getcode().startswith(code) && z.getcity(). tolowercase().contains(city)) lines.add(z); return lines; private static String[][] codes = "0800", "Høje Taastrup", "0900", "København C", Oto ważna metoda search () używana do wyszukiwania kodów pocztowych. Tutaj należy szczególnie zauważyć, że zwraca List <Zipcode>, a zatem listę obiektów Zipcode, które spełniają kryteria wyszukiwania. Następnie jest klasa MainActivity: package dk.data.torus.zipcodes; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.view; import android.widget.edittext; import android.widget.listview; import java.util.*; import android.widget.arrayadapter; public class MainActivity extends AppCompatActivity private Zipcodes zipcodes = new Zipcodes(); protected void oncreate(bundle savedinstancestate)

20 super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); public void onclick(view view) EditText text1 = (EditText) findviewbyid(r.id.edittext1); EditText text2 = (EditText) findviewbyid(r.id.edittext2); if (view.getid() == R.id.button1) text1.settext(""); text2.settext(""); else if (view.getid() == R.id.button2) List<Zipcode> list = zipcodes.search(text1.gettext().tostring().trim(), text2.gettext().tostring().trim()); ArrayAdapter<Zipcode> adapter = new ArrayAdapter<Zipcode>(this, android.r.layout. simple_list_item_1, list); ListView lv = (ListView) findviewbyid(r.id.listview1); lv.setadapter(adapter); Klasa ma instancję klasy Zipcodes, a zatem dostępne są kody pocztowe. Jeśli chodzi o moduł obsługi zdarzeń, tylko kod przycisku Szukaj zawiera coś nowego. Podczas wyszukiwania należy użyć wyniku, aby zaktualizować składnik ListView, który występuje w ArrayAdapter dla obiektów Zipcode. Tutaj parametry nie są od razu oczywiste. Pierwszy to odniesienie do bieżącego obiektu, a zatem obiektu, który składa się z ListView. Drugi parametr wygląda tajemniczo, ale oznacza stałą, która jest zdefiniowana jako część Androida i wskazuje, że jest to adapter ListView. Ostatnim parametrem są obiekty, dla których inicjowany jest komponent ListView. Adapter, o którym mowa, jest następnie wykorzystywany do inicjalizacji komponentu.

21 ĆWICZENIE 2: LUDZIE Musisz napisać program podobny do powyższego przykładu, który otworzy poniższe okno. U góry znajdują się dwa pola wprowadzania, a na dole znajduje się ListView. W dwóch górnych polach musisz mieć możliwość wpisania nazwiska osoby, a po kliknięciu OK nazwisko należy wstawić do widoku listy. W poniższym przykładzie wprowadzono 4 nazwy. Możesz rozwiązać ćwiczenie w sposób opisany poniżej: 1. Utwórz nowy projekt w Android Studio, który możesz nazwać People. 2. Utwórz wszystkie teksty w pliku string.xml. 3. Napisz projekt, to znaczy dodaj wszystkie widżety, przeciągając je z przybornika i upuszczając je do drzewa komponentów, a następnie dostosuj kod XML, ale bez dodawania procedur obsługi zdarzeń. 4. Przetestuj program w emulatorze i powtarzaj, dopóki nie pomyślisz, że wszystko wygląda ładnie. 5. Dodaj prostą klasę modelową Osoba reprezentująca osobę po imieniu i nazwisku. 6. Dodaj listę <Person> do MainActivity. 7. Dodaj adapter między listą a ListView. Należy pamiętać, że adapter tworzy formę powiązania danych między listą a komponentem. 8. Napisz moduł obsługi zdarzeń do przycisku Wyczyść. 9. Napisz moduł obsługi zdarzeń do przycisku OK, który (jeśli wprowadzono zarówno nazwisko, jak i imię) musi utworzyć obiekt Osoba i dodać go do listy.

22 Następnie program powinien zostać zakończony. 3 UKŁAD Tu zajmę się nieco bardziej układami, które oczywiście były już częścią poprzednich przykładów, ale chodzi o to, jak umieścić komponenty w oknie, dopasowując w ten sposób to, co wiesz od Swing jako menedżerów układu. Na tym tle (i ze znajomością paneli w JavaFX) stosunkowo łatwo jest zająć się działaniem układów, co pokazują również poprzednie przykłady. Istnieje jednak pewna składnia, a poniższe nie są odniesieniem, ale zamiast tego pokażę na przykładach, co jest możliwe. 3.1 UKŁAD WZGLĘDNY Jako przykład pokażę ulepszoną wersję programu z rozdziału 1, która jest ulepszona przez konwersję między stopniami Fahrenheita i Celsjusza: Oprócz tego główna różnica polega na tym, że użyty został inny menedżer układu, który nazywa się RelativeLayout. Punktem wyjścia jest nowy projekt, który nazwałem Konwertuj. Po utworzeniu projektu Android Studio utworzyło następujący projekt interfejsu użytkownika (czyli main_activity.xml): <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="dk.data.torus.convert.mainactivity">

23 <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="hello World" app:layout_constraintbottom_tobottomof="parent" app:layout_constraintleft_toleftof="parent" app:layout_constraintright_torightof="parent" app:layout_constrainttop_totopof="parent" /> </android.support.constraint.constraintlayout> Projekt zawiera menedżera układu o nazwie ConstraintLayout i jak wrócę do później, możesz zauważyć, że zdefiniowano dwa atrybuty android: layout_width i android: layout_height, oba o wartości match_parent. Oznacza to, że układ powinien zastosować całą przestrzeń, ponieważ element nadrzędny - a to powie ekran - udostępnia, i dotyczy to zarówno szerokości, jak i wysokości. W tym układzie Android Studio wstawiło widget TextView, który chcę usunąć. Następnie dodałem RelativeLayout do okna układu i z przybornika uporządkowałem bieżące widżety do układu, tak że prawie wszystkie widżety są teraz dodawane do okna w prawidłowej hierarchii (w której zmieniłem nazwy poszczególnych osób) widżety): W rezultacie wszystkie widżety znajdują się w lewym górnym rogu okna, a Android Studio wygenerował następujący kod XML: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="dk.data.torus.convert.mainactivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textview"

24 android:layout_width="wrap_content" android:text="textview" /> android:layout_height="wrap_content" <TextView android:layout_width="wrap_content" android:text="textview" /> android:layout_height="wrap_content" <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:inputtype="textpersonname" android:text="name" /> <RadioGroup android:layout_width="wrap_content" android:layout_height="wrap_content"> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="radiobutton" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="radiobutton" /> </RadioGroup> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" /> <TextView android:layout_width="wrap_content" android:text="textview" /> android:layout_height="wrap_content" <TextView android:layout_width="wrap_content" android:text="textview" /> android:layout_height="wrap_content" <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:ems="10" android:inputtype="textpersonname" android:text="name" /> <RadioGroup android:layout_width="wrap_content" android:layout_height="wrap_content"> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="radiobutton" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="radiobutton" /> </RadioGroup>

25 <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" /> </RelativeLayout> </android.support.constraint.constraintlayout> W tym miejscu należy szczególnie zwrócić uwagę na wartości, które Android Studio przypisał dla Androida: układ_szerokość i android: układ_wyżej. W przypadku RelativeLayout jest to match_parent, co oznacza, że powinien zastosować całą przestrzeń udostępnianą przez komponent nadrzędny, a tutaj jest ConstraintLayout, który wypełnia całe okno. W przypadku innych komponentów wszędzie jest używana wrap_content, co oznacza, że rozmiar komponentu jest określony przez zawartość, a jeśli weźmiesz TextView jako przykład, jest to tekst komponentu. Po tym, jak opisałem powyżej, bezkrytycznie wypełniłem widżety w oknie, moim zadaniem jest, aby ładnie siedziały i tutaj menedżer układu wchodzi do obrazu, ponieważ tutaj jest RelativeLayout. Jak sama nazwa wskazuje, ustawia poszczególne widżety względem siebie, określając atrybuty, więc mam proces, w którym dostosowuję kod XML, dodając atrybuty, dopóki nie jest tak, jak chcę. W ramach tego procesu nazywam też poszczególne widżety, aby miały nieco wyraźniejsze nazwy niż przypisane przez Android Studio. Poniżej znajduje się wypełniony plik XML: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#f5f5ba" tools:context="dk.data.torus.convert.mainactivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp"> <TextView android:id="@+id/lblhead1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginbottom="10dp" android:text="kilometers / miles" android:textsize="24dp"/> <TextView android:id="@+id/lbldist" android:layout_width="wrap_content" android:layout_below="@id/lblhead1" android:text="distance" /> android:layout_height="wrap_content" android:layout_alignbaseline="@id/txtdist" <EditText android:id="@+id/txtdist"

26 android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginleft="10dp" android:inputtype="numbersigned numberdecimal"/> <RadioGroup android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="10dp"> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:checked="true" android:text="miles to kilometers" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="kilometers to miles" /> </RadioGroup> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="10dp" android:text="clear" android:onclick="distclear"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="10dp" android:text="convert" android:onclick="distconvert"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="20dp" android:layout_marginbottom="10dp" android:text="fahrenheit / celsius" android:textsize="24dp"/> <TextView android:id="@+id/lbltemp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/lblhead2" android:layout_margintop="20dp" android:layout_alignbaseline="@id/txttemp" android:text="temperature" /> <EditText android:id="@+id/txttemp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/lblhead2" android:layout_toendof="@id/lbltemp" android:layout_marginleft="10dp" android:inputtype="numbersigned" /> <RadioGroup android:id="@+id/group2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/txttemp" android:layout_margintop="10dp">

27 <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:checked="true" android:text="fahrenheit to celsius" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="celsius to fahrenheit" /> </RadioGroup> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="10dp" android:text="clear" android:onclick="tempclear"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="10dp" android:text="convert" android:onclick="tempconvert"/> </RelativeLayout> </android.support.constraint.constraintlayout> Poniżej krótko wspomnę, co się stało. W ConstraintLayout zdefiniowałem kolor tła, aw RelativeLayout zdefiniowałem margines 20. Nie ma znaczenia, gdzie są umieszczone poszczególne widżety, ale są to ogólne ustawienia, które są nawet niezależne od bieżącego menedżera układu. Dla pierwszego widgetu TextView zmieniłem nazwę na lblhead1, a następnie zdefiniowałem margines 10 poniżej komponentu. Zmieniłem również tekst (tekst do wyświetlenia na ekranie) i zdefiniowałem rozmiar czcionki. Następny widget TextView nazwałem lbldist, a następnie w systemie Android: layout_below zdefiniowałem, że komponent powinien znajdować się pod lblhead1. W tym miejscu pojawia się układ względny. Następnie w systemie Android: layout_alignbaseline zdefiniowałem tekst, który ma być wyświetlany na tej samej linii bazowej, co dla następującego składnika, którym jest pole wejściowe, a celem jest wyrównanie dwóch widgetów pionowo względem siebie. Tutaj należy szczególnie zauważyć, że w XML można odwoływać się do widżetu (txtdist), który nie został jeszcze zdefiniowany. Jest to kolejny zdefiniowany widżet, a oprócz nazwy zmienianej na txtdist, należy zauważyć, że android: szerokość_komputera została zmieniona na fill_parent, co oznacza, że szerokość komponentu powinna wypełnić resztę przestrzeni jako komponent nadrzędny (tutaj RelativeLayout ) odłożył na bok, tzn. musi wykorzystać resztę szerokości okna. Ponadto zdefiniowane są trzy atrybuty, w przypadku których w przypadku systemu Android: układ_do_endof składnik powinien znajdować się po prawej stronie składnika TextField, a w systemie Android: układ_poniżej powinien znajdować się pod tekstem nagłówka, a na końcu w systemie Android: układ_marginleft, że jest trochę miejsca między pole wejściowe i tekst z przodu. Następnym widgetem jest RadioGroup. Nie ma tu wiele do wyjaśnienia, ale nadałem mu nazwę i zdefiniowałem, że powinna znajdować się poniżej pola wejściowego i że musi być margines 10 w polu wejściowym. Jeśli chodzi o dwa widżety RadioButton, nie ma też wiele do zauważenia, poza tym, że ponownie zmieniłem nazwy i wskazuję, że należy sprawdzić pierwszy. Zwróć także uwagę na atrybut android: layout_weight. W rzeczywistości nie jest to konieczne, ale wstawione przez Android Studio i oznacza, że należy użyć całej wysokości, ale w innych kontekstach jest to ważne.

28 Następnie podążamy za dwoma (górnymi) przyciskami i w porównaniu do tego, co zostało już wyjaśnione, nie ma nic nowego, ale należy zauważyć, że dla obu przycisków są określone procedury obsługi zdarzeń. Reszta kodu XML jest w zasadzie powtórzeniem powyższego, a wynikiem tego jest to, że poszczególne widżety są ładnie do siebie dopasowane. Procedura może wydawać się nieco kompleksowa i jest, ale przy odrobinie praktyki jest w rzeczywistości dość bezpiecznym, a także stosunkowo skutecznym sposobem zaprojektowania złożonego okna. Rzeczywiste okno jest w rzeczywistości związane ze złożonym telefonem komórkowym i rzadko powinno być bardziej złożone. Należy zauważyć, że tym razem nie zdefiniowałem tekstów jako zasobów, ale bezpośrednio w kodzie XML. Nie ma żadnych powodów, tylko dla uproszczenia pisania kodu. Z tyłu jest kod Java, a tutaj Konwerter klas został rozszerzony o dwie nowe metody konwersji statycznej. Klasa MainActivity ma teraz cztery procedury obsługi zdarzeń dla każdego z czterech przycisków. Wszystkie są proste i nie chcę tutaj wyświetlać kodu. Następnie aplikacja jest kompletna i może być przetłumaczona i przetestowana w emulatorze, a nawet może zostać zainstalowana na telefonie, jak opisano w części wprowadzającej. 3.2 UKŁAD LINIOWY W pierwszych przykładach tej książki użyłem LinearLayout, który jest menedżerem układu, który komponuje komponenty w rzędzie lub kolumnie. Można go natychmiast porównać z VBox i HBox w JavaFX, podobnie jak menedżery układu JavaFX (i Swing) można zagnieżdżać i można rozwiązać wiele problemów z układem za pomocą LinearLayout. Poniższy przykład nazywa się ButtonApp i wyświetla 6 przycisków na ekranie za pomocą dwóch zagnieżdżonych menedżerów LinearLayout: Aplikacja pokazuje tylko 6 przycisków i nie mają żadnej funkcji, więc jedynym kodem, który ma się wyświetlić, jest main_activity.xml: <?xml version="1.0" encoding="utf-8"?>

29 <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="dk.data.torus.buttonapp.mainactivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="20dp" android:padding="20dp" android:layout_weight="1" android:textsize="24dp" android:text="a" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:padding="10dp" android:layout_weight="1" android:textsize="24dp" android:text="b" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="30dp" android:padding="20dp" android:layout_weight="1" android:textsize="24dp" android:text="c" /> </LinearLayout> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:textsize="24dp" android:layout_weight="2" android:layout_gravity="center" android:text="d" /> <Button android:layout_width="50dip" android:layout_height="wrap_content" android:textsize="24dp" android:layout_weight="1" android:layout_gravity="right" android:text="e" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:textsize="24dp" android:layout_weight="3" android:text="f" /> </LinearLayout> </android.support.constraint.constraintlayout> Układ zaczyna się od LinearLayout i ma atrybut android: orientacja, który mówi, że komponenty powinny być ustawione pionowo. Pierwszym elementem jest nowy LinearLayout, a zatem układ zagnieżdżony, a jego orientacja jest natomiast pozioma. Należy tutaj zauważyć, że ustawia on system

30 Android: layout_height na wrap_content, aby nie przejmował całego okna. Wewnętrzny LinearLayout zawiera trzy przyciski z tekstami odpowiednio A, B i C, a wynik jest taki, że są ułożone poziomo. Dla każdego przycisku zdefiniowany jest margines wskazujący, ile miejsca powinno być na zewnątrz przycisku. Dopełnienie jest również zdefiniowane i określa, jak odległość powinna być od tekstu do krawędzi komponentu (jeśli jest to komponent z ramką). Dla wszystkich trzech przycisków android: layout_weight ma wartość 1, co oznacza, że muszą one równo dzielić przestrzeń, a tym samym uzyskać tę samą szerokość. Zewnętrzny LinearLayout ma, oprócz elementu LinearLayout powyżej, trzy przyciski, które następnie są ułożone pionowo pod układem za pomocą przycisków A, B i C. Trzy dolne przyciski D, E i F mają wagi 2, 1 i 3. Oznacza to, że dzielą one przestrzeń pionową w proporcjach 2/6, 1/6 i 3/6. W odniesieniu do szerokości elementów należy zauważyć, że dla D szerokość jest określana dla zawartości, natomiast dla E szerokość bezwzględna jest podana. W przypadku F jest to szerokość elementu nadrzędnego, a tym samym szerokość okna. Należy również zwrócić uwagę na atrybut android: layout_gravity, który wskazuje wyrównanie. Wcześniej LinearLayout był bardzo używanym menedżerem układu i nadal ma sens w sytuacjach, w których potrzebny jest bardzo prosty układ. 3.3 TABLELAYOUT Użyłem tego menedżera układu w poprzednim rozdziale w związku z aplikacją kodu pocztowego i nie chcę pokazywać innych przykładów, ale w rzeczywistości jest wiele do wyjaśnienia. Najlepiej jest myśleć o tym jak o tabeli HTML, która obsługuje pojęcia takie jak colspan i umieszczanie widżetów w określonych kolumnach, ale w zasadzie jest to łatwy w użyciu menedżer układu. 3.4 GRIDLAYOUT Istnieje również menedżer układu o nazwie GridLayout, który zasadniczo odpowiada GridPane w JavaFX. Zasadniczo jest to menedżer układu, który dzieli ekran na kilka komórek, a następnie możesz załadować składniki do menedżera, a jeśli nic więcej, umieści wszystkie widżety w dużym wierszu, ale możesz określić liczbę kolumn wskazuje to, ile kolumn powinno być. Możesz także zdefiniować liczbę wierszy, a także zdefiniować zakres dla poszczególnych komórek. Program IntCalc to prosty kalkulator o następującym układzie:

31 Kalkulator działa sam na liczbach całkowitych, wykonując na przykład dzielenie liczb całkowitych. Pole wejściowe jest tylko do odczytu, a liczby można wprowadzać tylko za pomocą przycisków. Wyrażenia należy wprowadzać w postaci postfiksowej, wprowadzając operator po argumentach. Na przykład, jeśli chcesz obliczyć następnie musisz wpisać 23 i kliknąć Enter, co oznacza, że 23 zostaną zapisane na stosie. Następnie wpisz 19, a następnie kliknij przycisk plus, a program obliczy sumę zawartości wyświetlacza i liczby wyskakujących ze stosu, po czym wyświetlacz zostanie zaktualizowany z wynikiem. Polecenia w dolnym rzędzie mogą nie być całkiem oczywiste, ale! określa silnię zawartości wyświetlacza, ^ podnosi moc, a _ zmienia znak zawartości wyświetlacza. Wreszcie C to polecenie, które usuwa zawartość ekranu, ale jednocześnie usuwa zawartość stosu, chociaż prawdopodobnie powinny to być dwa polecenia. Program jest prosty i składa się wyłącznie z activity_main.xml i MainActivity.java. Sekcja XML dużo wypełnia, a poniżej pokazałem tylko mniejszą część, ponieważ sama reszta odnosi się do większej liczby przycisków, które oczywiście są w zasadzie identyczne: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="dk.data.torus.intcalc.mainactivity"> <GridLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:columncount="5"> <EditText android:id="@+id/txtdisplay" android:layout_width="0dp" android:layout_height="60dp" android:layout_columnweight="1"

32 android:layout_gravity="fill_horizontal" android:textsize="24dp" android:layout_columnspan="5" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_columnweight="1" android:gravity="center" android:layout_gravity="fill_horizontal" android:textsize="24dp" android:onclick="modclicked" android:text="%" /> <Button android:layout_width="0dp" android:layout_columnweight="1" android:layout_height="wrap_content" android:gravity="center" android:layout_gravity="fill_horizontal" android:textsize="24dp" android:onclick="divclicked" android:text="/" /> <Button android:layout_width="0dp" android:layout_height="wrap_content" android:layout_columnweight="1" android:gravity="center" android:layout_gravity="fill_horizontal" android:textsize="24dp" android:onclick="mulclicked" android:text="*" /> </GridLayout> </android.support.constraint.constraintlayout> Najpierw zauważ, że GridLayout jest zdefiniowany z 5 kolumnami. Tutaj możesz również określić liczbę wierszy, ale nie jest to konieczne, ponieważ wiersze są określane na podstawie kodu XML. Pierwszy widget to EditText i należy pamiętać, że jego szerokość jest ustawiona na 0. Jest tak, ponieważ szerokość jest określona przez atrybut wagi i atrybut gravverty, które są atrybutami używanymi przez GridLayout do określania, ile składników powinno się wypełnić. Należy również pamiętać, że dla tego komponentu zdefiniowano rozpiętość kolumny wynoszącą 5, ponieważ wyświetlacz maszyny powinien wypełniać całą szerokość okna. Na koniec zauważ, że komponent ma identyfikator, do którego należy się odwoływać w kodzie Java, ale jest to również jedyny widżet układu, który ma identyfikator. Wszystkie pozostałe (20) widżety są składnikami przycisku, a tak naprawdę nie ma wiele do zapamiętania, poza którymi atrybutami zdefiniowano rozmiar. Ponieważ waga w dowolnym miejscu wynosi 1, oznacza to, że wszystkie mają taką samą szerokość, jak gravirty jest ustawiony na fill_horizontal. Kod Java również wypełnia się, ponieważ istnieje 20 programów obsługi zdarzeń, a następujące elementy to tylko część kodu: package dk.data.torus.intcalc; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.*;

33 import android.widget.*; import java.util.*; public class MainActivity extends AppCompatActivity private Stack<Long> stack = new Stack(); private boolean newvalue = false; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); EditText text = (EditText) findviewbyid(r.id.txtdisplay); text.setkeylistener(null); text.setenabled(false); public void oneclicked(view view) insert(view, "1"); public void addclicked(view view) calc2(view, '+'); private void insert(view view, String ch)

34 EditText text = (EditText) findviewbyid(r.id.txtdisplay); try if (newvalue) long value = Long.parseLong(text.getText().toString()); stack.push(value); text.settext(ch); newvalue = false; else text.settext(text.gettext() + ch); catch (Exception ex) text.settext("error"); private void calc2(view view, char opr) EditText text = (EditText) findviewbyid(r.id.txtdisplay); try long value2 = Long.parseLong(text.getText().toString()); long value1 = stack.pop(); switch (opr) case '+': value1 += value2; break; case '-': value1 -= value2; break; case '*': value1 *= value2; break; case '/': value1 /= value2; break; case '%': value1 %= value2; break; case '^': value1 = (long)math.pow(value1, value2);

35 text.settext("" + value1); newvalue = true; catch (Exception ex) text.settext("error"); Klasa ma dwie zmienne instancji, przy czym pierwsza to stos, a druga służy do kontrolowania, czy zawartość ekranu powinna być umieszczana na stosie po kliknięciu cyfry. Konstruktor jest rozszerzony o dwie instrukcje służące do ustawiania wyświetlania tylko do odczytu, dzięki czemu nie można bezpośrednio wprowadzać liczb. Pamiętaj, że oznacza to, że wirtualna klawiatura nie jest wyświetlana. Po kliknięciu przycisku cyfry wykonywana jest metoda insert (). Testuje zmienną newvalue, a jeśli jest to prawda, oznacza to wprowadzenie nowej liczby, a metoda próbuje parsować zawartość wyświetlacza na liczbę całkowitą i umieścić go na stosie. Następnie kliknięta cyfra jest wstawiana jako wartość wyświetlacza. Jeśli newvalue ma wartość false, nic więcej się nie dzieje, niż kliknięta cyfra jest dodawana do zawartości wyświetlacza. Po kliknięciu operatora z dwoma argumentami procedura obsługi zdarzeń wywołuje metodę clac2 (). Analizuje zawartość wyświetlacza i wysuwa stos i wykonuje faktyczne obliczenia, po których ekran jest aktualizowany. Zauważ, że newvalue jest ustawione na true, ponieważ wynik musi zostać dodany do stosu przy następnym kliknięciu przycisku. Zamiast tego kliknij operatora z jednym argumentem (i powie to dla bieżącej maszyny! I _) wywoływana jest metoda calc1 (), która zmienia wartość wyświetlacza. 3.5 KONSTRUKCJA Jako ostatni menedżer układu chciałbym wspomnieć o ConstraintLayout, który jest menedżerem układu zdefiniowanym przez Android Studio jako domyślny dla działania. Zasadniczo działa trochę jak RelativeLayout, ale jest bardziej elastyczny, a celem jest zaprojektowanie złożonego układu wyłącznie za pomocą myszy i edytora układu Android Studio. Oznacza to, że możesz przeciągać widżety do okna z przybornika i przeciągać je w wybrane miejsca za pomocą myszy. W ten sposób możesz stworzyć gotowy projekt bez konieczności samodzielnego pisania XML. Aby zdefiniować pozycję komponentu widoku, musi on mieć co najmniej jedno wiązanie poziome i co najmniej jedno wiązanie pionowe, przy czym każde wiązanie stanowi załącznik lub wyrównanie do innego widoku lub układu macierzystego. Każde ograniczenie określa zatem pozycję widoku wzdłuż osi poziomej lub pionowej, ale często dla każdej osi będzie więcej ograniczeń. Jeśli upuścisz widok w edytorze układu, nie będzie on miał żadnych

36 ograniczeń, ale pozostanie tam, gdzie zostanie upuszczony. Prawdopodobnie istnieją pewne atrybuty, a przykładem może być: Po wykonaniu tych czynności dla obu widżetów kod XML wygląda następująco: <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_marginstart="16dp" android:layout_height="wrap_content" android:layout_margintop="24dp" android:text="button" app:layout_constraintbottom_tobottomof="parent" app:layout_constraintend_toendof="parent" app:layout_constrainthorizontal_bias="0.5" app:layout_constraintstart_tostartof="parent" app:layout_constrainttop_tobottomof="@+id/edittext" /> <EditText android:id="@+id/edittext" android:layout_width="wrap_content" android:layout_height="46dp" android:layout_marginstart="8dp" android:layout_margintop="32dp" android:ems="10" android:inputtype="textpersonname" android:text="name" app:layout_constraintend_toendof="parent" app:layout_constrainthorizontal_bias="0.5" app:layout_constraintstart_tostartof="parent" app:layout_constrainttop_totopof="parent" /> a Android Studio przekonwertowało wszystkie ograniczenia edytora na rzeczywiste ograniczenia, po których program można przetłumaczyć i uruchomić, a komponenty znajdują się zgodnie z powyższym kodem XML. Oczywiście wymaga to trochę nauki, jak korzystać z edytora układu, ale jeśli nie piszesz aplikacji na Androida codziennie, warto spróbować, ponieważ możesz mieć na uwadze składnię XML, która nie jest wszędzie, łatwa rozumieć. Za pomocą ConstraintLayout możesz zaprojektować w pełni funkcjonalną aplikację bez spełniania kodu XML. Z drugiej strony, jeśli często piszesz aplikacje mobilne, może faktycznie płacić za pracę bezpośrednio w XML. Ucząc się, jak korzystać z różnych menedżerów układu oraz jak określać pozycję i wyrównanie widżetów, otrzymujesz bardzo stabilny i bezpieczny układ oraz szybko i bardzo sprawnie pracujesz nad złożonymi czynnościami. Tutaj powinieneś pamiętać, że zawsze możesz przejść do trybu projektowania, aby zobaczyć, jak to wszystko wygląda.

37 3.6KONTENERY Android oferuje również wiele komponentów, które mogą wyświetlać rodzinę obiektów. Istnieją widżety zwane kontenerami i chociaż menedżerowie układów nie są bezpośrednio kontenerami, mają one coś wspólnego z układem. W rzeczywistości pokazałem już przykład w aplikacji Zipcodes, która korzystała z ListView, który jest kontenerem, który może wyświetlać wiele obiektów. Jeśli kontener zawiera więcej obiektów, niż jest miejsca na ekranie, możesz przewijać zawartość, a także możesz powiązać moduł obsługi zdarzeń z kontenerem, który uruchamia się za każdym razem, gdy wybierzesz obiekt. Zasadniczo różne kontenery są używane w ten sam sposób i wykorzystują źródło danych z bieżącymi obiektami, sam kontener, taki jak ListView, a następnie adapter, którego zadaniem jest aktualizacja kontenera. Zacznę od programu, który pokazuje przegląd królów duńskich: tam, gdzie powyżej, kliknięto Svend Estridsen, w wyniku czego okres rządowy pojawia się w dwóch najwyższych polach. Interfejs użytkownika jest dość prosty i zawiera oprócz dwóch LinearLayout trzy widżety: <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.constraintlayout xmlns:android=" xmlns:app=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#e5e532" tools:context="dk.data.torus.thekings.mainactivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margin="20dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal">

38 <EditText android:layout_width="fill_parent" android:layout_weight="1" android:layout_height="wrap_content" android:textsize="24dp" android:layout_marginright="5dp" android:padding="10dp" android:textcolor="#ffffff" android:background="#ff0000"/> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:textsize="24dp" android:layout_marginleft="5dp" android:padding="10dp" android:textcolor="#ffffff" android:background="#ff0000"/> </LinearLayout> <ListView android:layout_width="match_parent" android:layout_margintop="20dp"/> android:layout_height="match_parent" </LinearLayout> </android.support.constraint.constraintlayout> Istnieją dwa widżety EditText, a tutaj nie ma nic nowego do wyjaśnienia, ale zwróć uwagę na nazwy i zdefiniowane atrybuty. Ten ostatni to ListView, w którym oprócz nazwy nie ma nic, co można zauważyć, ale jest to kontener i widget, który należy zainicjować danymi, i do którego ma zostać dołączony moduł obsługi zdarzeń. Zdarza się to w kodzie Java. Po pierwsze, zasób danych i punkt początkowy to następująca klasa modelu: package dk.data.torus.thekings; public class King private String name; private int from; private int to; public King(String name, int from, int to) this.name = name; this.from = from; this.to = to; public String getname()

39 return name; public int getfrom() return from; public int getto() return to; public String tostring() return name; Jest to również bardzo prosta klasa, która nie zawiera niczego poza tym, czego potrzebuje obecny program, a tutaj należy szczególnie zwrócić uwagę na metodę tostring (), która zwraca wartość pojawiająca się dla każdego obiektu w kontenerze ListView. Jako druga część zasobu danych klasa Kings udostępnia bieżące obiekty King: package dk.data.torus.thekings; import java.util.*; public class Kings private List<King> list = new ArrayList(); public Kings() for (String[] arr : data) list.add(new King(arr[0], Integer.parseInt(arr[1]), Integer.parseInt(arr[2])));

40 public List<King> getkings() return list; private static final String[][] data = "Gorm den Gamle", "0", "958", "Harald Blåtand", "958", "987", ; gdzie pokazałem tylko kilka danych. Klasa jest oczywiście pseudo, ponieważ wszystkie dane są zakodowane na stałe i jasne jest, że dane te powinny pochodzić z innego źródła, takiego jak plik, baza danych lub równoważne, ale ponieważ nie pokazałem jeszcze, jak to zrobić, trzeba poczekać później, ale to nie zmienia zasady. Adapter jest w rzeczywistości podstawową koncepcją w Androidzie, a jego celem jest odłączenie źródła danych od prezentacji, aby programista działał w ten sam sposób, niezależnie od tego, jakie jest źródło danych i niezależnie od tego, który widget listy jest używany aby wyświetlić dane. W takim przypadku kod klasy znajduje się w klasie MainActivity: package dk.data.torus.thekings; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.*; import android.widget.*; import android.widget.adapterview.*; import java.util.*; public class MainActivity extends AppCompatActivity private List<King> kings = (new Kings()).getKings();

41 private EditText from; private EditText to; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); from = (EditText) findviewbyid(r.id.txtfrom); to = (EditText) findviewbyid(r.id.txtto); disable(from); disable(to); ListView view = (ListView) findviewbyid(r.id.lstkings); view.setadapter(new ArrayAdapter<King>(this, android.r.layout.simple_list_item_1, kings)); view.setonitemclicklistener(new OnItemClickListener() public void onitemclick(adapterview<?> parent, View view, final int position, long id) update(position); ); public void update(int position) int a = kings.get(position).getfrom(); int b = kings.get(position).getto(); from.settext(a == 0? "" : "" + a); to.settext(b == 9999? "" : "" + b);

42 private void disable(edittext view) view.setkeylistener(null); view.setenabled(false); Początkowo tworzona jest lista obiektów typu King, która jest następnie źródłem danych programu. Ponadto zmienne są zdefiniowane dla dwóch komponentów EditText i oba są inicjowane w oncreate (). Ponadto dla obu obiektów wywoływana jest metoda disable (), która wyłącza oba pola wejściowe, aby nie można było wprowadzać tekstu. Następnie definiowane jest odwołanie do składnika ListViev i inicjowane za pomocą adaptera: new ArrayAdapter<King>(this, android.r.layout.simple_list_item_1, kings) Typ to ArrayAdapter, który jest adapterem używanym dla źródła danych, które jest tablicą lub listą, a zatem źródłem danych, w którym poszczególne obiekty są identyfikowane przez indeks. Ponadto parametr (dla typu ogólnego) informuje, że adapter reprezentuje obiekty King. Konstruktor ma trzy parametry, przy czym pierwszy to obiekt (tutaj bieżący obiekt), do którego należy zainicjować kontener, to element członkowski, a ostatni parametr to zasób danych. Następnie jest środkowy parametr, który mówi, jak obiekty powinny być prezentowane przez kontener, a tutaj jest stała, której znaczenie nie jest łatwe do zrozumienia, ale mówi, że obiekt powinien być prezentowany jako ciąg, a zatem jest to wartość metody tostring () obiektu do wyświetlenia. Na koniec moduł obsługi zdarzeń jest dołączony do komponentu ListView i dzieje się tak z metodą setonitemclicklistener (), gdzie parametrem jest OnItemClickListener, który jest interfejsem definiującym moduł obsługi zdarzeń. Ma cztery parametry, przy czym najważniejsza jest pozycja, która wskazuje indeks klikniętego obiektu (tabulowany palcem). W takim przypadku wykonuje metodę update (), która aktualizuje dwa górne pola wejściowe z okresem rządów króla. Chcę pokazać odmianę powyższej aplikacji, którą nazwałem SelectKings. Program otwiera następujący telefon, który ponownie pokazuje królów duńskich, ale tym razem są dwa składniki ListView, w których u góry widać królów wybranych na dole. Na dole możesz tym razem zaznaczyć obiekty za pomocą pól wyboru i możesz zaznaczyć wiele i wybrać więcej obiektów. W tym przykładzie wybrano dwa, a jeśli odznaczysz pola wyboru, nazwy znikną z górnego ListView. Ponownie program składa się z pliku XML do zdefiniowania interfejsu użytkownika, a także klasy MainActivity (oraz klas modeli King i Kings), a program przede wszystkim pokazuje, jak dynamicznie aktualizować interfejs użytkownika za pomocą adaptera.

43 Układ w pliku XML jest tym razem następujący: <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_margin="20dp"> <ListView android:id="@+id/lstkings1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginbottom="20dp"/> <ListView android:id="@+id/lstkings2" android:layout_width="match_parent" android:layout_weight="1" android:drawselectorontop="false" /> android:layout_height="match_parent" android:choicemode="multiplechoice" </LinearLayout> Nie ma wiele do zapamiętania, ale powinieneś zauważyć, jak wskazać na dole, że wybór wielokrotności powinien być możliwy. Ponadto zwróć uwagę, jak w projekcie z layout_weight zdefiniować, że dwa komponenty powinny równo dzielić przestrzeń. Najważniejsza rzecz dzieje się w części Java, a tutaj klasy King i Kings pozostają niezmienione, a MainActivity zostaje zmieniona: package dk.data.torus.selectkings; import android.support.v7.app.appcompatactivity; import android.os.bundle;

44 import android.view.*; import android.widget.*; import android.widget.adapterview.*; import java.util.*; public class MainActivity extends AppCompatActivity private List<King> kings = (new Kings()).getKings(); private List<String> lines = new ArrayList(); private ListView view; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); view = (ListView) findviewbyid(r.id.lstkings1); ListView view2 = (ListView) findviewbyid(r.id.lstkings2); view2.setadapter(new ArrayAdapter<King>(this, android.r.layout.simple_list_item_multiple_choice, kings)); view2.setonitemclicklistener(new OnItemClickListener() public void onitemclick(adapterview<?> parent, View view, final int position, long id) update(kings.get(position)); ); private void update(king king)

45 String line = tostring(king); if (!lines.remove(line)) lines.add(line); view.setadapter(new ArrayAdapter<String>(MainActivity.this, android.r.layout.simple_list_item_1, lines)); private String tostring(king king) if (king.getfrom()!= 0 && king.getto()!= 9999) return String.format("%s: %d %d", king. getname(), king.getfrom(), king.getto()); if (king.getfrom()!= 0) return String.format("%s: %d -", king.getname(), king.getfrom()); if (king.getto()!= 9999) return String.format("%s: %d", king.getname(), king.getto()); return king.getname(); Tak jak w poprzednim przykładzie, tworzona jest lista obiektów King, która jest używana jako źródło danych dla dolnego ListView. Ponadto tworzona jest kolejna lista ciągów znaków, która jest używana jako źródło danych dla górnego ListView, a także zdefiniowane jest odwołanie do górnego ListView. Powodem jest to, że nie trzeba znaleźć odwołania za każdym razem, gdy klikniesz dolny ListView. To odwołanie jest inicjowane w funkcji oncreate (). Tutaj inicjowany jest również dolny ListView, zasadniczo podobny do poprzedniego przykładu, ale tym razem używany jest inny parametr dla drugiego parametru dla adaptera: android.r.layout.simple_list_item_multiple_choice Mówi, że tym razem obiekty króla powinny być nie tylko wyświetlane jako ciągi znaków, ale z kolejnym polem wyboru i że powinno być możliwe wybranie wielu. Zamiast tego, gdybyś mógł wybrać tylko jeden, napisałbyś: android.r.layout.simple_list_item_single_choice

46 Dolny ListView ma taki sam sposób, jak w poprzednim przykładzie, dołączając moduł obsługi zdarzeń, ale teraz wykonuje coś innego. Metoda update () przekształca bieżący obiekt King w ciąg, a jeśli ten ciąg jest już w liniach źródła danych, jest usuwany i dodawany w inny sposób. Adapter jest następnie używany do aktualizacji górnego ListView. Jako ostatni przykład królów program SpinKings otwiera następujące okno: Program jest prawie identyczny z programem TheKings i istnieje tylko jedna różnica, że zamiast ListView stosuje się Spinner, który odpowiada ComboBox, jak znasz go z Swinga lub JavaFX. Kod jest zasadniczo taki sam, a dla części XML istnieje tylko jedna różnica, w której element ListView został zastąpiony elementem Spinner: <Spinner android:id="@+id/lstkings" android:layout_width="match_parent" android:layout_height="wrap_content" android:drawselectorontop="true" android:layout_margintop="20dp"/> Jeśli chodzi o kod Java, dwie klasy modelowe King i Kings pozostają niezmienione, ale klasa MainActivity zostało zmienione i jest to tylko metoda oncreate (): protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); from = (EditText) findviewbyid(r.id.txtfrom); to = (EditText) findviewbyid(r.id.txtto); disable(from); disable(to);

47 Spinner view = (Spinner) findviewbyid(r.id.lstkings); view.setadapter(new ArrayAdapter<King>(this, android.r.layout.simple_spinner_item, kings)); view.setonitemselectedlistener(new OnItemSelectedListener() public void onitemselected(adapterview<?> parent, View view, int position,long id) update(position); public void onnothingselected(adapterview<?> parent) from.settext(""); to.settext(""); ); Oto najważniejszy oczywiście moduł obsługi zdarzeń, który tym razem ma innego detektora, czyli interfejs definiujący dwie metody. ĆWICZENIE 3: LUDZIE 1 Zacznij od utworzenia kopii projektu z ćwiczenia 2. Możesz wywołać kopię dla People1. Musisz dodać kilka zmian. Interfejs użytkownika musi być prawie taki sam. Jedyną różnicą jest to, że należy dodać nowy przycisk (patrz poniżej). Po wprowadzeniu jednej lub więcej osób i wstawieniu ich do kontenera ListView, musisz mieć możliwość kliknięcia osoby, a następnie nazwisko osoby musi zostać wstawione do dwóch górnych pól wprowadzania, aby można było edytować nazwiska. Po kliknięciu przycisku OK nie należy dodawać żadnej nowej osoby, ale listę należy zaktualizować o zmienione nazwisko. Jeśli kliknąłeś nazwę i została ona wstawiona w pola wprowadzania, musisz także móc usunąć nazwę, klikając nowy przycisk. Pamiętaj, że nowy przycisk od początku jest wyłączony i musi być włączony tylko wtedy, gdy nazwa została kliknięta na liście.

48 4. INTERAKCJA UŻYTKOWNIKA W tym rozdziale przyjrzę się nieco bardziej podstawowym interakcjom użytkownika, w tym sposobom korzystania z menu i okien dialogowych. Chcę jednak zacząć od wirtualnej klawiatury. Urządzenie z Androidem może mieć klawiaturę sprzętową, ale większość urządzeń, w tym smartfony, ma wirtualną klawiaturę, która pojawia się po kliknięciu pola wprowadzania. Pole wejściowe jest widżetem EditText, ale jeśli spojrzysz na edytor projektu pod paletą Tekst, zobaczysz, że istnieje wiele opcji, a każda z nich mówi, jak wyświetlić zawartość, ale przede wszystkim, której wirtualnej klawiatury użyć: Każda linia wstawi widok EditText, a różne opcje wskazują wartość atrybutu InputType. Jak widać, istnieje wiele opcji, w szczególności należy zauważyć, że istnieją typowe zadania, takie jak wprowadzanie tekstu, adresów , liczb itp. Ważne jest, aby pamiętać, że atrybut InputType mówi

49 przede wszystkim, jak powinna wyglądać wirtualna klawiatura, a zatem jakie są klawisze. Na przykład, jeśli wybrałeś Liczba, otrzymasz klawiaturę, która ma tylko cyfry, możesz się zalogować, a zatem bardzo ograniczoną klawiaturę: Pamiętaj, że nie możesz przełączyć się na klawiaturę z literami. Za pomocą programu EnterText można eksperymentować i pokazywać znaczenie wirtualnych klawiatur. Program otwiera okno zawierające 5 widgetów TextView i 5 widgetów EditText. Nie chcę tutaj pokazywać pliku activity_main.xml, ponieważ jedyną rzeczą, na którą należy zwrócić uwagę, jest wartość atrybutu InputText, ale należy zwrócić uwagę na następujące kwestie: - Górny jest pusty, co oznacza, że możesz wprowadzić wszystko. - Następny ma wartość textpassword, co oznacza, że to, co wpisujesz, pojawia się w postaci kropek. - Trzeci ma numer wartości i oznacza, że możesz wprowadzić liczby całkowite. - Czwarty ma wartość numberdecimal, dzięki czemu można wprowadzać liczby dziesiętne. - Ten ostatni ma wartość textmultiline i oznacza, że możesz wprowadzić więcej wierszy, a następnie to, co znasz jako TextArea

50 Jak wspomniano powyżej, nie pokażę kodu XML, ponieważ wypełnia się dużo bez dodawania tak wielu nowych. Zasadniczo jest to TableLayout z widgetami TextView i EditText, ale menedżer układu jest umieszczony w ScrollView: <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <TableLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="10dp"> </TableLayout> </ScrollView> Oznacza to, że użytkownik może przewijać zawartość w pionie. Jeśli chcesz przewijać w poziomie, użyj zamiast tego programu HorizontalScrollView. 4.1 MENU KONTEKSTOWE Menu są często używane w aplikacjach na telefony komórkowe, aw tym rozdziale pokażę ci, jak dołączyć menu kontekstowe do kontrolki. Jako przykład użyję programu TheKings, jak pokazałem powyżej, do którego chcę dołączyć menu kontekstowe dla pojedynczych królów w komponencie ListView. Zacząłem od kopii projektu, który nazwałem AboutKings. Interfejs użytkownika jest dokładnie taki sam, więc zmiany dotyczą tylko sekcji Java. Dlatego nie chcę ponownie wyświetlać kodu XML interfejsu użytkownika. Klasa Kings zawiera tablicę statyczną, w której dane dla królów duńskich są zdefiniowane jako stałe. Dla każdego króla istnieją trzy wartości, ale tablica jest rozszerzana o czwartą warto ale jeśli chodzi o program, informacje nie są krytyczne (to tylko tekst), a tekst nie jest tłumaczony na angielski. Podobnie jak w tym rozszerzeniu, klasa King jest również rozszerzana o dodatkowy atrybut, który zwraca ten opis, a klasa jest rozszerzana za pomocą metody getking (), która zwraca ciąg będący imieniem króla i okresem rządowym. Potem jest klasa MainActivity, która jest bardzo rozbudowana: public class MainActivity extends AppCompatActivity public static final int MENU_NAME = Menu.FIRST + 1; public static final int MENU_TEXT = Menu.FIRST + 2 ; private List<King> kings = (new Kings()).getKings(); private EditText from; private EditText to; protected void oncreate(bundle savedinstancestate)

51 super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); from = (EditText) findviewbyid(r.id.txtfrom); to = (EditText) findviewbyid(r.id.txtto); disable(from); disable(to); ArrayAdapter<King> adapter = new ArrayAdapter<King>(this, android.r.layout. simple_list_item_1, kings); ListView view = (ListView) findviewbyid(r.id.lstkings); view.setadapter(adapter); view.setonitemclicklistener(new OnItemClickListener() public void onitemclick(adapterview<?> parent, View view, final int position, long id) update(position); ); registerforcontextmenu(view); public void oncreatecontextmenu(contextmenu menu, View v, ContextMenu.ContextMenuInfo menuinfo) menu.add(menu.none, MENU_NAME, Menu.NONE, "King"); menu.add(menu.none, MENU_TEXT, Menu.NONE, "Description"); public boolean oncontextitemselected(menuitem item)

52 AdapterView.AdapterContextMenuInfo menuinfo = (AdapterView.AdapterContextMenuInfo) item.getmenuinfo(); King king = kings.get(menuinfo.position); switch (item.getitemid()) case MENU_NAME: Toast.makeText(this, king.getking(), Toast.LENGTH_LONG).show(); return (true); case MENU_TEXT: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.settitle(king.getname()); builder.setmessage(king.gettext()); builder.setpositivebutton("close", new DialogInterface.OnClickListener() public void onclick(dialoginterface dialog, int which) ); builder.show(); return (true); return (super.oncontextitemselected(item)); public void update(int position) int a = kings.get(position).getfrom(); int b = kings.get(position).getto(); from.settext(a == 0? "" : "" + a); to.settext(b == 9999? "" : "" + b); private void disable(edittext view) view.setkeylistener(null); view.setenabled(false);

53 Najpierw zdefiniowane są dwie stałe, które definiują dwie pozycje menu w menu kontekstowym. W rzeczywistości muszą to być unikalne liczby całkowite, ale dokumentacja zaleca robienie tego, jak pokazano w tym przykładzie, ponieważ Android tworzy inne elementy menu w innych kontekstach i muszą mieć unikalny identyfikator w ramach tej samej aktywności. Ostatnia instrukcja w oncreate () mówi, że menu kontekstowe musi być zarejestrowane dla komponentu ListView programu. Jeśli istnieją inne widżety, które powinny mieć menu kontekstowe, należy je zarejestrować w ten sam sposób. Następnie istnieje metoda oncreatecontextmenu (), która tworzy menu. W tym przypadku jest to proste z dwoma elementami menu, ale oczywiście może być więcej. Wreszcie istnieje moduł obsługi zdarzeń, który w tym przypadku jest wykonywany za każdym razem, gdy element menu jest wybierany w menu kontekstowym. Ten parametr to wybrany element menu. Po pierwsze, która linia jest klikana i określany jest odpowiedni obiekt King. Jeśli jest to pierwszy element menu, nic się nie dzieje poza prostym Toastem z tekstem będącym imieniem króla i okresem rządowym. Tam jest komunikat, który jest wyświetlany przez okno i automatycznie znika po krótkim czasie określonym przez urządzenie. Wszystko, co możesz kontrolować, to to, że parametr może wskazywać, czy zajmuje to dużo czasu (kilka sekund = 3,5), czy mniej czasu (= 2 sekundy). Poniżej znajduje się okno, w którym aktywowane jest menu kontekstowe: Sposób aktywacji menu kontekstowego zależy od wersji Androida (nie ma myszy, którą można kliknąć prawym przyciskiem myszy), ale w nowszych wersjach Androida dzieje się tak, gdy przytrzymujesz palec na komponencie, aż menu się wyskoczy. Drugi element menu otwiera alert, który jest prostym polem komunikatu. Tworzysz alert za pomocą zaawansowanego konstruktora, który jako parametr wskazuje działanie, które powinno być właścicielem. Następnie konstruktor określa, co powinno znajdować się w linii tytułowej i samej wiadomości. Następnie musisz zdefiniować, które przyciski powinny być. Mogą istnieć dwa przyciski zdefiniowane za pomocą metod setpositivebutton () i setnegativebutton (), w tym przypadku jest tylko jeden. Po kliknięciu przycisku okno dialogowe zamyka się bez względu na to, który to przycisk, ale dla przycisku przypisana jest obsługa zdarzeń. W tym

54 przypadku jest pusty, ale w innych sytuacjach akcja może zostać wykonana po kliknięciu przycisku. Jako przykład pokazano poniżej wygląd alertu po kliknięciu nazwy. To, co mówi tekst, nie jest ważne, ale tekst został tak wybrany, że nie można wyświetlić całego tekstu, ale automatycznie pojawia się pasek przewijania. 4.2 GŁÓWNE MENU Następnie pokażę, jak zdefiniować menu główne, które jest wywoływane w menu opcji w Androidzie. Jako przykład chciałbym użyć zmodyfikowanej wersji aplikacji SelectKings, którą nazwałem MoreKings. Jeśli otworzysz program, pojawi się okno, jak pokazano poniżej, w którym znajduje się ListView, który pokazuje królów z polem wyboru, ale na pasku tytułowym, zwanym oknem ActionBar, są teraz trzy pionowe kropki wskazujące, że jest menu. Menu zawiera dwa elementy menu, przy czym jeden element menu usuwa wszystkich królów ze znacznikiem wyboru w polach wyboru, podczas gdy drugi element menu wykonuje resetowanie, a tym samym ponownie wstawia wszystkich królów. Program nadal ma takie samo menu kontekstowe jak w poprzednim przykładzie. Ze względu na to ostatnie klasy King i Kings są zastępowane przez odpowiednie klasy z poprzedniego przykładu. activity_main.xml jest prawie identyczny z odpowiednim plikiem z SelectKings, z tą różnicą, że jeden składnik ListView jest usuwany, więc część XML jest teraz bardzo prosta. Nowe rzeczy, na które należy zwrócić uwagę, dotyczą tylko MainActivity.java: package dk.data.torus.selectkings; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.*; import android.widget.*;

55 import android.util.*; import android.app.alertdialog; import android.content.*; import java.util.*; public class MainActivity extends AppCompatActivity public static final int MENU_NAME = Menu.FIRST + 1; public static final int MENU_TEXT = Menu.FIRST + 2 ; public static final int MENU_REMOVE = Menu.FIRST + 3; public static final int MENU_RESET = Menu.FIRST + 4; private List<King> kings; private ListView view; private ArrayAdapter<King> adapter; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); view = (ListView) findviewbyid(r.id.lstkings2); reset(); registerforcontextmenu(view); public void oncreatecontextmenu(contextmenu menu, View v, ContextMenu.ContextMenuInfo menuinfo) menu.add(menu.none, MENU_NAME, Menu.NONE, "King"); menu.add(menu.none, MENU_TEXT, Menu.NONE, "Description"); public boolean oncontextitemselected(menuitem item)

56 AdapterView.AdapterContextMenuInfo menuinfo = (AdapterView.AdapterContextMenuInfo) item.getmenuinfo(); King king = kings.get(menuinfo.position); switch (item.getitemid()) case MENU_NAME: Toast.makeText(this, king.getking(), Toast.LENGTH_LONG).show(); return (true); case MENU_TEXT: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.settitle(king.getname()); builder.setmessage(king.gettext()); builder.setpositivebutton("close", new DialogInterface.OnClickListener() public void onclick(dialoginterface dialog, int which) ); builder.show(); return (true); return (super.oncontextitemselected(item)); public boolean oncreateoptionsmenu(menu menu) menu.add(menu.none, MENU_RESET, Menu.NONE, "Reset"); menu.add(menu.none, MENU_REMOVE, Menu.NONE, "Remove"); return(super.oncreateoptionsmenu(menu)); public boolean onoptionsitemselected(menuitem item) switch (item.getitemid())

57 case MENU_RESET: reset(); return(true); case MENU_REMOVE: remove(); return(true); return(super.onoptionsitemselected(item)); private void reset() kings = (new Kings()).getKings(); view.setadapter(adapter = new ArrayAdapter<King>(this, android.r.layout.simple_list_item_multiple_choice, kings)); private void remove() SparseBooleanArray checkeditems = view.getcheckeditempositions(); if (checkeditems!= null) for (int i = checkeditems.size() 1; i >= 0; --i) if (checkeditems.valueat(i)) King king = kings.get(checkeditems.keyat(i)); adapter.remove(king); for (int i = 0; i < view.getcount(); ++i) view.setitemchecked(i,false) Kiedy widzisz kod, nie ma w nim tak wiele tajemnic, chociaż został on bardzo zmieniony w porównaniu do SelectKings. Najpierw zauważ, że cztery stałe, które będą identyfikować pozycje menu. Ponadto istnieją trzy zmienne instancji, które odnoszą się do danych programu, składnika ListView, a także adaptera. Składnik ListView jest inicjowany w metodzie reset (), wywoływanej z metody oncreate (). Powodem jest to, że metodę tę należy wykonać również po wybraniu opcji Resetuj w menu. Dwie następujące metody są metodami z poprzedniego przykładu i są używane do tworzenia menu kontekstowego oraz do obsługi zdarzeń. Metoda oncreateoptionsmenu () tworzy menu główne. Nie ma wiele do wyjaśnienia oprócz parametrów i wartości Menu. BRAK. Jak sama nazwa wskazuje, oznacza to oczywiście, że nie masz wartości parametru. W tym przypadku jest pytanie, że elementy

58 menu można podzielić na grupy, które nie są tutaj używane. Metoda onoptionsitemselected () jest powiązaną procedurą obsługi zdarzeń, która jest również prosta, ale wywołuje metodę remove () w celu usunięcia wszystkich elementów wybranych w składniku ListView. W tym miejscu należy szczególnie zwrócić uwagę na sposób określania indeksów (pozycji) wybranych elementów oraz że wynikiem jest SparseBooleanArray, który można traktować jako tablicę indeksów wybranych elementów. Należy również zwrócić uwagę na ostatnią instrukcję wymaganą do usunięcia znaczników wyboru w komponencie ListView. W wyniku tego, podobnie jak w poprzednim programie, można łatwo powiązać menu z aplikacją 4.3 OKREŚL MENU W XML W powyższych przykładach menu są zdefiniowane w Javie i nie ma w tym nic złego, ale możesz to również zrobić jako zasób w XML, a tak naprawdę zaleca się, aby to zrobić, częściowo w celu oddzielenia kodu i definicja interfejsu użytkownika, a częściowo w celu ułatwienia wersji językowych aplikacji. Ponadto jest to bardzo proste. Projekt LastKings jest kopią powyższego projektu, ale podczas res katalogu utworzyłem nowy podkatalog z menu nazw, który zawiera dwa dokumenty xml: Treść pierwszego dokumentu to:

59 <menu xmlns:android=" <item android:title="respond" /> <item android:title="description" /> </menu> a drugi jest w zasadzie identyczny: <menu xmlns:android=" <item android:id="@+id/remove_menu" android:title="remove" /> <item android:id="@+id/reset_menu" android:title="reset" /> </menu> W kodzie Java należy zmienić metody oncreatecontextmenu () i oncreateoptionsmenu () public void oncreatecontextmenu(contextmenu menu, View v, ContextMenu.ContextMenuInfo menuinfo) new MenuInflater(this).inflate(R.menu.context_menu, menu); public boolean oncreateoptionsmenu(menu menu) new MenuInflater(this).inflate(R.menu.main_menu, menu); return(super.oncreateoptionsmenu(menu)); i 4 stałe dla pozycji menu można usunąć. Procedury obsługi zdarzeń muszą również zostać zmienione, aby nie korzystały ze stałych, ale zamiast identyfikatorów z dokumentów XML. Jako przykład pokazano poniżej jedną z dwóch procedur obsługi zdarzeń: public boolean onoptionsitemselected(menuitem item) switch (item.getitemid()) case R.id.reset_menu: reset(); return(true); case R.id.remove_menu: remove(); return(true); return(super.onoptionsitemselected(item)); a potem wszystko znowu działa.

60 ĆWICZENIE 4: IMAGEAPP Utwórz nowy projekt, który możesz nazwać ImageApp. Kod źródłowy książki ma folder o nazwie obrazy zawierający cztery obrazy. Skopiuj te obrazy do swojego projektu: ImageApp / app / src / main / res / drawable Obrazy to img1.jpg, img2.jpg, img3.jpg i img4.jpg, a po skopiowaniu zdjęć są dodawane jako zasoby do projektu. Projekt musi (w emulatorze) otworzyć następujące okno, które ma dwa komponenty w postaci TextView i ImageView: W pliku strings.xml musisz zdefiniować 4 ciągi, które są nazwami ptaków, które pokazują obrazy: <resources> <string name="app_name">imageapp</string> <string name="lbl_img1">great Tit</string> <string name="lbl_img2">starling</string> <string name="lbl_img3">jackdaw</string> <string name="lbl_img4">robin Redbreast</string> </resources> Do komponentu TextView należy zdefiniować menu kontekstowe z czterema pozycjami menu (patrz poniżej). Menu musi być zdefiniowane w formacie XML, a jeśli wybierzesz element menu, program musi wyświetlić odpowiedni obraz i zaktualizować składnik TextView o poprawną nazwę.

61 Po przetestowaniu programu możesz opcjonalnie zastąpić zdjęcia własnymi zdjęciami i być może mieć 6 obrazów zamiast O AKTYWNOŚCI Chcę zakończyć ten rozdział, patrząc trochę bliżej klasy Activity, i jak pokazano w poprzednich przykładach, każda aplikacja mobilna ma obiekt Activity. Można by pomyśleć o Działaniu jako o obiekcie reprezentującym okno programu i implementującym logikę używaną przez aplikację, dlatego program może mieć więcej działań. Aktywność może być w czterech trybach 1. Uruchamiany, gdy pojawia się działanie, zwykle w wyniku wykonania przez użytkownika czynności w celu uruchomienia aplikacji. 2. Uruchomienie, w którym użytkownicy faktycznie widzą Twoją aktywność, po wykonaniu wszystkich różnych kroków konfiguracji. 3. Killed, czyli stan, w którym system operacyjny Android zdecydował się zakończyć aplikację. 4. Zamknij, w którym usuwane są wszystkie trwałe informacje o stanie. Zmiany są wprowadzane na podstawie metod wywołania zwrotnego, gdzie oncreate () jest przykładem, ale jest kilka innych i wszystkie metody można zastąpić. Poniżej wymienię główne metody wywołania zwrotnego. Funkcja oncreate () jest wykonywana, gdy działanie rozpoczyna swój cykl życia, zwykle dlatego, że użytkownik zażądał działania lub działanie zostało ponownie uruchomione z powodu zmian w środowisku, na przykład z powodu rotacji urządzenia. Dla ponownego uruchomienia oncreate () ma parametr typu Bundle, który może zawierać informacje o stanie działania. Zasadniczo, oncreate () jest używany do: 1. Załaduj układy używane przez działanie, aby można było zbudować komponenty interfejsu użytkownika w metodzie onstart ().

62 2. Zainicjuj zmienne instancji działania. Niektóre zadania dotyczą funkcji oncreate () i dotyczą przede wszystkim ponownego uruchomienia działania, w tym śledzenia istniejących zasobów globalnych od czasu ostatniego działania. Na przykład, jeśli programowo zmienisz układ w zależności od interakcji użytkownika z aplikacją. onstart (), który jest wykonywany po tym, jak oncreate () utworzy wymagane obiekty z definicji układu i wykona inne prace inicjalizacyjne, jest onstart (), którego zadaniem jest przedstawienie bieżących elementów interfejsu użytkownika dla użytkownika. Rzadko zachodzi potrzeba zastąpienia tej metody. A jeśli tak, ważne jest, aby wywołać funkcję super.onstart (). onresume () jest wykonywany bezpośrednio przed pojawieniem się interfejsu użytkownika, a metoda działa prawie tak samo jak onstart (), ale jest wykonywana w połączeniu z innym przełącznikiem stanu, jak widać na poniższym diagramie stanów: Funkcja onpause () jest wykonywana po przełączeniu aplikacji w stan tła po zawieszeniu aplikacji przez system Android. Patrząc z programisty, można użyć tej metody, aby zapewnić zapisanie danych po zawieszeniu aplikacji.

63 onstop () wysyła aktywność w tle i można myśleć o metodzie jako przeciwieństwo onstart (), a aktywność nie jest już widoczna dla użytkownika, podczas gdy widok i właściwości nadal istnieją i są przenoszone do onresume () i onstart () jeśli są wykonywane. Zauważ, że onstop () nie jest koniecznie wykonywany, jeśli Android zdecyduje się zakończyć aplikację i dlatego rzadko zastępuje się tę metodę. onrestart () jest wykonywany przy zmianie stanu z zatrzymania na start, a następnie pozwala w pewnym stopniu zdecydować, jak zrestartować działanie. Funkcja ondestroy () jest wykonywana, gdy działanie jest zamknięte, ale należy pamiętać, że dotyczy ono działania, a nie całej aplikacji. Metodę można zastosować tylko do czyszczenia związanego z bieżącą aktywnością. Powyższy diagram stanu powinien pokazywać, gdzie i kiedy wykonywane są różne metody wywołania zwrotnego w związku z przesunięciem stanu. W powyższych przykładach użyłem tylko oncreate (), ale ponieważ przykłady wykorzystują więcej funkcji telefonu, więcej powyższych metod wywołania zwrotnego jest również interesujących. Istnieje kilka metod związanych ze zmianą stanu działania i można je zastąpić, a jako przykład chciałbym wymienić dwie: 1. onrestoreinstancestate (), który jest wykonywany, gdy użytkownik opuszcza działanie, klikając przycisk Wstecz lub wykonując inną logikę, która jest częścią aplikacji, a metody można użyć w sytuacjach, w których zachodzi potrzeba zapisania danych użytkownika. 2. onsaveinstancestate (), który jest odpowiedzialny za przechowywanie informacji o stanie działania, głównie związanych z ondestroy (). 4.5 WIELE DZIAŁAŃ Jako ostatni w tym rozdziale pokażę przykład aplikacji, która ma dwie czynności. Aplikacja jest trywialna i powinna pokazywać tylko, jak dodać więcej działań do aplikacji. Należy pamiętać, że aplikacja może mieć wszystkie potrzebne działania. Zacząłem od projektu o nazwie MoreActivities, a po utworzeniu projektu istnieje jedno działanie o nazwie MainActivity, którego układ nazywa się activity_main.xml. Następnie mam pod plikami projektu prawym przyciskiem myszy aplikację i wybrałem New Activity Empty Activity a w następnym oknie mam dla nazw wybranych SecondActivity i activity_second. xml. W rezultacie mój projekt zawiera teraz dwa działania. Do pierwszego (czyli MainActivity) dodałem moduł obsługi zdarzeń: package dk.data.torus.moreactivities; import android.support.v7.app.appcompatactivity; import android.os.bundle;

64 import android.content.intent; import android.view.*; public class MainActivity extends AppCompatActivity protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); public void openactivity(view view) Intent intent = new Intent(this, SecondActivity.class); startactivity(intent); Nie ma wiele do wyjaśnienia, poza odnotowaniem, że przewodnik otwiera inną aktywność, w wyniku czego ekran telefonu zmienia treść i pokazuje inną aktywność. Kod XML i tym samym układ są następujące: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=" xmlns:tools=" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp" tools:context="dk.data.torus.moreactivities.mainactivity"> <TextView android:id="@+id/lbl_main" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerhorizontal="true" android:text="go to the second activity" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content"

65 android:text="open Activity" android:layout_margintop="50dp" android:layout_centerhorizontal="true" android:onclick="openactivity" /> </RelativeLayout> który jest niezwykle prostym układem z tekstem i przyciskiem. W przypadku drugiej aktywności musi się zdarzyć prawie to samo. Kod XML jest w zasadzie identyczny. Pojawia się tylko kolejny tekst, a przycisk ma inną procedurę obsługi zdarzeń: public class SecondActivity extends AppCompatActivity protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_second); public void closeactivity(view view) finish(); To wszystko, a następnie aplikacja może zostać przetłumaczona i przetestowana, a wynikiem jest aplikacja z dwiema czynnościami. PROBLEM 1: LOANAPP W książce Java 3 (a także gdzie indziej) pokazałem aplikację, która implementuje kalkulator kredytu, w którym użytkownik może obliczyć spłatę kredytu. Tym razem pożyczka jest każdorazowo pożyczką dożywotnią, a program musi otworzyć następujące okno:

66 który zawiera tylko etykiety, pola wprowadzania i przyciski. W dwóch górnych polach należy wprowadzić odpowiednio koszty finansowania zewnętrznego i kwotę główną pożyczki, natomiast w dwóch kolejnych polach należy podać liczbę lat spłaty kredytu i liczbę okresów rocznych. W ostatnim polu musisz mieć możliwość wprowadzenia stopy procentowej, która jest wprowadzana jako stopa procentowa w procentach rocznie. Po kliknięciu przycisku OBLICZ, program musi obliczyć termin płatności i pokazać go w polu po tekście Płatność, który jest tekstem do edycji tylko do odczytu. Przed obliczeniem (po kliknięciu przycisku OBLICZ) program musi sprawdzić poprawność danych: 1. Koszt nie może być ujemny 2. Pożyczka musi być dodatnia 3. Liczba lat musi być liczbą całkowitą od 1 do 60 (obie włącznie) 4. Liczba terminów w ciągu roku musi być liczbą całkowitą od 1 do 12 (obie włącznie) 5. Stopa procentowa musi być dodatnia i mniejsza niż 50 W przypadku błędu program musi wyświetlić komunikat o błędzie w postaci prostego Toast. Poniżej pokazano okno po obliczeniu pożyczki:

67 Jeśli klikniesz przycisk AMORTYZACJA, program musi otworzyć inne działanie, które pokazuje plan amortyzacji: W tym miejscu należy szczególnie zauważyć, że pasek akcji okna ma przycisk Wstecz. Zadanie polega na tym, aby dowiedzieć się, jak dodać ten przycisk - jest to dość proste i możesz spróbować przeszukać Internet. Rzeczywista tabela jest pokazana za pomocą GridView. Jest również częścią zadania, aby dowiedzieć się, jak korzystać z GridView, ale jest prawie taki sam jak TextView. 5 PLIKI W świetle powyższych przykładów pokazane tematy mogą być dobrym krokiem w rozwoju aplikacji na telefony komórkowe, ale telefon oferuje szereg innych usług wykraczających poza zwykłe komputery, na których mogę wymienić SMS-y i telefony, GPS, aparaty fotograficzne i więcej. Są to obiekty, które najpierw omówię w poniższej książce, ale możliwe jest również zapisywanie danych w plikach i bazach danych, co jest niezbędne w wielu aplikacjach, aw tym i następnym rozdziale skupię się na tym, jak to zrobić. W tym rozdziale omówimy pliki, w tym sposób manipulowania systemem plików, tak jak na zwykłym komputerze, ale chcę zacząć od czegoś innego, a mianowicie plików, które można tylko

68 odczytać. Jeśli istnieją pliki, które są zainteresowane tylko bieżącą aplikacją, pliki można zapisać jako pliki zasobów w aplikacji. Przykładami mogą być tekst, obrazy, audio i więcej. 5.1 CZYTANIE ZASOBÓW Jeśli utworzysz projekt w Andoid Studio, pod plikami projektu będą dwa katalogi java i res, przy czym ten ostatni zawiera pliki zasobów. Są to pliki spakowane kodem programu w pliku apk. Tutaj znajdziesz między innymi układ podkatalogu, który zawiera activity_main.xml, który definiuje interfejs użytkownika aplikacji i w tej samej lokalizacji będą inne dokumenty XML do układu innych działań. Poznałeś także plik strings.xml w wartościach podkatalogu. Udostępnianie danych w ten sposób ma kilka zalet, takich jak: - Łatwo jest zdefiniować dane, które są zawsze dostępne dla programu. - Zapewnia separację kodu i danych. - Pozwala na umieszczenie zasobów w bibliotece, dzięki czemu mogą być używane przez wiele aplikacji. - Proste dane mogą być udostępniane w standardowym formacie, takim jak XML. Są też wady, między innymi: - Dane są zasadniczo tylko do odczytu, chociaż w zasadzie możliwa jest modyfikacja zawartości zasobu. - Zapewnienie aktualności danych może być problematyczne / uciążliwe. Aby pokazać przykład, jak to zrobić, wrócę do przykładu z królami duńskimi, które reprezentują dane, które rzadko się zmieniają. Są to zatem dane, które można wygodnie umieścić jako zasób, ale także dlatego, że są to dane, które nie wypełniają się zbyt wiele. Dane, o których mowa, są przechowywane w dokumencie XML o nazwie regents.xml i mają następującą zawartość: <regents> <regent name="gorm den Gamle" to="958"/> <regent name="harald Blåtand" from="958" to="987"/> <regent name="svend Tveskæg" from="987" to="1014"/> <regent name="harald 2." from="1014" to="1018"/> <regent name="frederik 9." from="1947" to="1972"/> <regent name="margrethe 2." from="1972"/> </regents> Następnie stworzyłem projekt, który nazwałem DanishRegents. Układ definiuje tylko jeden komponent: <ListView android:id="@+id/lstreg"

69 android:layout_width="match_parent" android:layout_height="match_parent" /> i jedyne, co należy zrobić, to wypełnić ListView nazwiskami królów duńskich. Aby udostępnić dane, utworzyłem podkatalog o nazwie raw i skopiowałem plik regents.xml do tego podkatalogu. Następnie dokument jest zasobem dla aplikacji. Następnie dodałem modelową klasę Regent, która może reprezentować regent, i oprócz nazwy klasa jest identyczna z klasą King, której użyłem wcześniej. Tam jest tylko klasa MainActivity: package dk.data.torus.danishregents; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.widget.*; import android.view.*; import java.util.*; import java.io.*; import javax.xml.parsers.*; import org.w3c.dom.*; import android.widget.adapterview.*; public class MainActivity extends AppCompatActivity List<Regent> regents = new ArrayList(); protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); try InputStream stream = getresources().openrawresource(r.raw.regents); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

70 Document doc = builder.parse(stream, null); NodeList nodes = doc.getelementsbytagname("regent"); for (int i = 0; i < nodes.getlength(); ++i) Element elem = (Element)nodes.item(i); String attr = elem.getattribute("from"); int from = attr == null attr.length() == 0? Integer.MIN_VALUE : Integer.parseInt(attr); attr = elem.getattribute("to"); int to = attr == null attr.length() == 0? Integer.MAX_VALUE : Integer.parseInt(attr); regents.add(new Regent(elem.getAttribute("name"), from, to)); stream.close(); catch (Exception e) ListView view = (ListView)findViewById(R.id.lstReg); view.setadapter(new ArrayAdapter<Regent>(this, android.r.layout.simple_list_item_1, regents)); view.setonitemclicklistener(new OnItemClickListener() public void onitemclick(adapterview<?> parent, View view, final int position, long id) Regent regent = regents.get(position); Toast.makeText(MainActivity.this, regent.getregent(), Toast.LENGTH_LONG).show(); );

71 Po pierwsze, zauważ, że istnieje wiele nowych instrukcji importu, między innymi dlatego, że program powinien czytać i analizować dokumenty XML. Klasa ma zmienną pojedynczej instancji, która jest Listą dla obiektów Regent, a zatem dla obiektów, które powinien wyświetlić komponent ListView. W przeciwnym razie klasa ma tylko funkcję oncreate (). Zaczyna się od załadowania zasobu. W tym miejscu powinieneś zwrócić uwagę na to, jak odwoływać się do zasobów programu za pomocą metody getresources () i jak załadować plik raw za pomocą metody openrawresource () oraz że wynikiem jest zwykły InputStream. Po udostępnieniu tego strumienia DocumentBuilder może odczytać dokument i parsować go jako XML, po czym można utworzyć bieżące obiekty Regent i zainicjować listę. Po załadowaniu danych i zainicjowaniu listy adapter jest dodawany do komponentu ListView. Ponadto dodano moduł obsługi zdarzeń, aby program wyświetlał Toast, jeśli klikniesz nazwę w komponencie ListView. Ćwiczenie 5: Kody pocztowe W sekcji 2.1 pokazuję kody pocztowe aplikacji, w których możesz wyszukiwać duńskie kody pocztowe. Zacznij od utworzenia kopii kodów pocztowych projektu. W katalogu res musisz utworzyć podkatalog o nazwie raw. Kod źródłowy książki zawiera plik zipcodes.txt, który zawiera duński kod pocztowy jako plik oddzielony przecinkami. Skopiuj ten plik do nowego katalogu raw. W klasie Kody pocztowe wszystkie kody pocztowe są zdefiniowane w tablicy statycznej. Musisz teraz usunąć tę tablicę i zmienić klasę, aby obiekty Zipcode były tworzone przez czytanie zawartości pliku zipcodes.txt zasobu. Możesz wykonać następujące czynności: 1. Usuń tablicę statyczną 2. Dodaj parametr typu InputStream do konstruktora klasy 3. Konstruktor musi następnie zainicjować listę kodów pocztowych, odczytując zawartość strumienia reprezentowanego przez parametr Pojedynczą zmianę należy dodać do klasy MainActivity. W oncreate () musisz utworzyć referencję do swojego zasobu i wysłać go jako parametr do konstruktora w klasie Zipcodes. Wtedy wszystko powinno znów działać. 5.2 PLIKI ZWYKŁE Możesz także korzystać ze zwykłych plików, które znasz z komputera, a to za mało, idzie to w ten sam sposób, jak opisano w książce Java 5 o IO. Główną różnicą jest to, że pliki mogą być przechowywane w dwóch miejscach, albo wewnętrznie, gdzie są przechowywane razem z programem w pamięci wewnętrznej, albo na zewnątrz, gdzie mogą być przechowywane na zewnętrznej karcie SD. Chcę tylko pokazać pierwszą opcję, ponieważ możliwość zdalnego zapisywania plików na karcie SD stanowi problem bezpieczeństwa w Androidzie, dlatego Google znacznie zaostrzyło wymagania dotyczące plików zewnętrznych i prawdopodobnie nie znalazły jeszcze ostatecznego rozwiązania. Możliwe jest otwarcie urządzenia, aby można było łatwo tworzyć pliki na karcie SD, ale nie jest to zalecane, więc patrzę tylko na pliki wewnętrzne, ale w odniesieniu do kodu różnica nie jest duża. Pliki tworzone wewnętrznie są przechowywane w pamięci telefonu, która w tym kontekście nazywana jest pamięcią wewnętrzną. Ma swoje wady i zalety, o których mogę wspomnieć:

72 - Pamięć wewnętrzna to coś, co zawsze istnieje i jest częścią dowolnego urządzenia z Androidem, ale ma ograniczony rozmiar i znacznie mniej niż to, co udostępnia karta SD i nie ma nieznacznego ryzyka, że jeśli aplikacje często zapisują pliki w pamięci wewnętrznej, więc że zostaną wypełnione. - Zasadniczo pliki przechowywane w pamięci wewnętrznej są powiązane z aplikacją i mogą Ta aplikacja może z niej korzystać tylko natychmiast. Jeśli plik jest używany przez inne aplikacje, konieczne są specjalne wysiłki, a w rzeczywistości nie jest intencją dzielenie się informacjami między aplikacjami za pomocą plików wewnętrznych. - Pliki przechowywane w pamięci wewnętrznej są postrzegane jako część aplikacji, które są skojarzone z aplikacją, a jeśli usuniesz aplikację, usuniesz również jej wewnętrzne pliki. Pliki wewnętrzne nadają się zatem przede wszystkim do przechowywania mniejszych ilości danych, które muszą być dostępne dla programu przy następnym uruchomieniu, ale jest to również potrzebne w wielu przykładach, więc wniosek nie polega na unikaniu używania plików wewnętrznych, ale pomyśl tylko o tym, do czego są używane. Jak wspomniano, pliki wewnętrzne są powiązane z aplikacją, a aplikacja ogólnie ma nieograniczony dostęp do pliku, a zatem może zarówno czytać, jak i zapisywać plik - aplikacja po prostu jest właścicielem pliku. Po otwarciu pliku możesz określić następujące tryby: - MODE_PRIVATE, jest to ustawienie domyślne i tylko aplikacja, która tworzy plik, może uzyskać dostęp do pliku - MODE_APPEND Poniżej spojrzę na przykład, który pokazuje, jak korzystać z pliku. 5.3 PRZECHOWYWANIE WEWNĘTRZNE Program jest prostym programem kontaktowym, w którym możesz wpisać imię i nazwisko, numer telefonu, adres i tekst dla osoby:

73 Po wprowadzeniu kontaktu (należy podać nazwę) możesz zapisać kontakt, zapisując go w pliku w pamięci wewnętrznej. Po kliknięciu przycisku POKAŻ zobaczysz poniższe okno, które pokazuje przegląd wprowadzonych kontaktów. Trzymając palec na kontakcie, otrzymasz menu kontekstowe z dwiema funkcjami, w których możesz usunąć kontakt (a następnie usunąć go z pliku) i wybrać, aby zobaczyć szczegóły kontaktu (patrz okno poniżej). Jest to zatem aplikacja składająca się z trzech działań. Nie chcę patrzeć na kod XML dla trzech układów, ponieważ tutaj nie ma nic nowego, więc poniższe informacje dotyczą głównie kodu Java. Oto dwie rzeczy, które powinieneś zauważyć: 1. jak zapisać do pliku, co jest głównym celem tego przykładu 2. jak przenieść parametr z jednego działania do drugiego Program wykorzystuje następującą klasę modelu, w której nie pokazałem metod pobierania i ustawiania:

74 public class Person implements Serializable private String name; private String phone; private String mail; private String text; public Person(String name, String phone, String mail, String text) this.name = name; this.phone = phone; this.mail = mail; this.text = text; public Person(String line) throws Exception String[] elems = line.split("\f"); if (elems.length!= 4) throw new Exception("Illegal text for person"); name = elems[0];

75 phone = elems[1].trim(); mail = elems[2].trim(); text = elems[3].trim(); public String getperson() StringBuilder builder = new StringBuilder(name); builder.append("\f"); builder.append(phone.length() == 0? "\t" : phone); builder.append("\f"); builder.append(mail.length() == 0? "\t" : mail); builder.append("\f"); builder.append(text.length() == 0? "\t" : text); return builder.tostring(); public String tostring() return name; public boolean equals(object obj) Klasa reprezentuje osobę o czterech pożądanych właściwościach. Pomysł polega na tym, że kontakty powinny być zapisywane jako wiersze tekstu w pliku, dlatego konieczne jest oddzielenie pól, aby można było ponownie odczytać w pliku. Należy użyć znaku separacji, który jest tylko znakiem, który nie pojawia się w polach tekstowych, a tutaj używam przesuwania strony (przesunięcie strony). Metoda getperson () zwraca w ten sposób ciąg znaków z polami osoby oddzielonymi kanałami formularzy. Należy zauważyć, że jeśli pole jest puste (jakie mogą być pola, jeśli nie jest to nazwa), karta zostanie zapisana. Można to nazwać obejściem, a przyczyną jest metoda split () w klasie String ignoruje puste pola. Klasa ma dwa konstruktory, a tutaj najpierw powinieneś zauważyć ten ostatni, który ma parametr String i zakłada, że łańcuch składa się z 4 pól oddzielonych formularzami. Pola są określane przez rozdzielenie ciągów znaków na pola za pomocą metody split (), i należy pamiętać, że dla ostatnich trzech pól wykonywana jest funkcja trim (), a celem jest usunięcie dowolnej zakładki wstawionej

76 powyższą metodą. Na koniec należy zauważyć, że klasa jest zdefiniowana Serializable. Powodem jest to, że powinna istnieć możliwość przeniesienia obiektu Person jako parametru z jednego działania do drugiego. Ta klasa jest główną częścią pracy nad zapisywaniem obiektów osoby w pliku. Odczytywanie i zapisywanie do pliku odbywa się w klasie Osoby, która reprezentuje wszystkie kontakty: public class Persons implements Serializable private static final String filename = "papersons"; private List<Person> persons = new ArrayList(); private transient Context context; public Persons(Context context) throws Exception this.context = context; FileInputStream stream = null; try stream = context.openfileinput(filename); catch (Exception ex) return; BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); for (String line = reader.readline(); line!= null; line = reader.readline()) try persons.add(new Person(line)); catch (Exception ex) reader.close();

77 public Person getperson(int n) return persons.get(n); public List<Person> getpersons() return persons; public void save(person person) throws Exception FileOutputStream stream = context.openfileoutput(filename, Context.MODE_APPEND); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stream)); writer.write(person.getperson()); writer.newline(); writer.close(); persons.add(person); public void remove(context context, Person person) throws Exception if (persons.remove(person)) FileOutputStream stream = context.openfileoutput(filename, Context.MODE_PRIVATE); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stream)); for (Person p : persons) writer.write(p.getperson()); writer.newline();

78 writer.close(); else throw new Exception("Person could not be removed"); Kiedy studiujesz kod, powinieneś najpierw zauważyć, że wszystkie podstawy są takie same, jakie znasz z IO w Javie, i że używane są nawet te same klasy. Klasa jest zdefiniowana jako Serializable, ponieważ powinna zostać przesłana jako parametr do działania. Klasa ma trzy zmienne, z których pierwsza to nazwa pliku, druga to ArrayList to Person, a druga to kontekst, który reprezentuje działanie. Służy do tworzenia pliku, ponieważ jest powiązany z działaniem. Zauważ, że jest zdefiniowany jako przejściowy. Powodem jest to, że nie należy go serializować, gdy obiekt Person zostanie przeniesiony do innego działania. Konstruktor klasy ładuje linie pliku i analizuje je do obiektów Person. Zasadniczo jest podobny do tych samych klas, których zwykle używa się do czytania pliku tekstowego w Javie. Jest tylko jedno miejsce, w którym jest coś nowego i tam otwiera się plik: stream = context.openfileinput (nazwa pliku) Dzieje się tak z metodą openfileinput (), która jest metodą w obiekcie kontekstowym, który otwiera plik w pamięci wewnętrznej i zwraca obiekt InputFileStream. Potem wszystko idzie tak, jak w przypadku innych plików tekstowych w Javie. Podczas zapisywania wprowadzonego kontaktu wywołujesz metodę save () z obiektem Person jako parametrem. Oto niewiele nowych, a jedyne jak otworzyć plik: context.openfileoutput(filename, Context.MODE_APPEND) który otwiera plik wyjściowy w pamięci wewnętrznej i znowu jest to metoda w obiekcie kontekstu. Metoda zwraca obiekt FileOutputStream. Plik zostanie otwarty w trybie dołączania, aby dodać do pliku, a jeśli plik nie istnieje, zostanie automatycznie utworzony. Wreszcie istnieje metoda remove (), aby usunąć osobę z pliku. Plik jest tym razem otwarty jako context.openfileoutput(filename, Context.MODE_PRIVATE) co oznacza, że istniejąca treść jest zastępowana. Metoda polega na zapisaniu całej zawartości listy osób z powrotem do pliku (ale nie na usuwanym obiekcie). Jest to konieczne, ponieważ jest to plik sekwencyjny i coś podobnego miałoby zastosowanie, gdybyś mógł zmienić informacje o kontakcie. Następnie jest klasa MainActivity: public class MainActivity extends AppCompatActivity private Persons persons; private EditText txtname; private EditText txtphone; private EditText txtmail; private EditText txttext;

79 protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); loadpersons(); txtname = (EditText)findViewById(R.id.txtName); txtphone = (EditText)findViewById(R.id.txtPhone); txtmail = (EditText)findViewById(R.id.txtMail); txttext = (EditText)findViewById(R.id.txtText); public void onclear(view view) clear(); public void onsave(view view) String name = txtname.gettext().tostring().trim(); String phone = txtphone.gettext().tostring().trim(); String mail = txtmail.gettext().tostring().trim(); String text = txttext.gettext().tostring().trim(); if (name.length() > 0) try persons.save(new Person(name, phone, mail, text)); Toast.makeText(this, getresources().getstring(r.string.msg_save), Toast.LENGTH_LONG).show(); clear(); catch (Exception ex) Toast.makeText(this, getresources().getstring(r.string.err_save), Toast.LENGTH_LONG).show();

80 public void onshow(view view) Intent intent = new Intent(this, ShowActivity.class); intent.putextra("persons", persons); startactivity(intent); private void clear() txtname.settext(""); txtphone.settext(""); txtmail.settext(""); txttext.settext(""); txtname.requestfocus(); private void loadpersons() try persons = new Persons(this); catch (Exception ex) Intent home = new Intent(Intent.ACTION_MAIN); home.addcategory(intent.category_home); home.setflags(intent.flag_activity_clear_top); startactivity(home); W oncreate () niewiele się dzieje poza tym, że metoda tworzy instancję zmiennych w 4 polach wejściowych, ale metoda wywołuje loadpersons (), która inicjuje zmienną osoby poprzez utworzenie nowego obiektu Persons, a tym samym odczytanie wszystkich kontaktów w pliku. Zwróć uwagę na

81 parametr, którym jest obiekt Context. Konstruktor w klasie Persons może zgłosić wyjątek, jeśli plik z tego lub innego powodu nie może zostać poprawnie odczytany. Jeśli tak, nie pozostaje nic innego jak zatrzymać aplikację, a metodę można postrzegać jako standardowy sposób na zatrzymanie aplikacji. Oprócz metody oncreate () klasa ma przede wszystkim trzy procedury obsługi zdarzeń dla trzech przycisków. Tutaj onsave () jest najbardziej wszechstronny, ponieważ musi utworzyć obiekt Person odpowiadający temu, co wprowadził użytkownik. W przeciwnym razie metoda nie robi nic więcej niż wywołanie metody save () w klasie Persons, a na koniec metoda pokazuje Toast, który informuje, czy kontakt został zapisany, czy nie. Moduł obsługi zdarzeń onshow () musi otworzyć inną aktywność i dzieje się tak samo, jak pokazano wcześniej z jedną różnicą: intent.putextra ( osoby, osoby); Wskazuje, że obiekt osoby muszą zostać wysłane jako parametr i zidentyfikowane przez kluczowe osoby. Klasa Intent ma wiele przesłonięć puextra (), w tym przesłonięcia dla wszystkich prostych typów i ciągów, ale istnieje również przesłonięcie dla obiektu możliwego do serializacji, dlatego klasy Person i Persons są zdefiniowane jako Serializable. Następnie jest klasa ShowActivity, która jest oknem pokazującym przegląd wszystkich kontaktów: public class ShowActivity extends AppCompatActivity private Persons persons; private ListView view; private ArrayAdapter<Person> adapter; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_show); Intent intent = getintent(); persons = (Persons)intent.getSerializableExtra("persons"); view = (ListView) findviewbyid(r.id.lstview); reset(); getsupportactionbar().setdisplayhomeasupenabled(true); registerforcontextmenu(view); public boolean onsupportnavigateup() finish(); return true;

82 public void oncreatecontextmenu(contextmenu menu, View v, ContextMenu.ContextMenuInfo menuinfo) new MenuInflater(this).inflate(R.menu.context_menu, menu); public boolean oncontextitemselected(menuitem item) AdapterView.AdapterContextMenuInfo menuinfo = (AdapterView.AdapterContextMenuInfo) item.getmenuinfo(); Person person = persons.getperson(menuinfo.position); switch (item.getitemid()) case R.id.details_menu: Intent intent = new Intent(this, DetailActivity.class); intent.putextra("person", person); startactivity(intent); return(true); case R.id.remove_menu: try persons.remove(this, person); reset(); Toast.makeText(this, getresources().getstring(r.string.msg_rem), Toast.LENGTH_LONG).show(); catch (Exception ex) Toast.makeText(this, getresources().getstring(r.string.err_rem), Toast.LENGTH_LONG).show(); return(true); return (super.oncontextitemselected(item));

83 private void reset() view.setadapter(adapter = new ArrayAdapter<Person>(this, android.r.layout.simple_list_item_1, persons.getpersons())); Kod wypełnia część, ale wypełnia się przede wszystkim moduł obsługi zdarzeń dla menu kontekstowego okna. Zwróć uwagę, jak metoda oncreate () określa parametr przesłany z MainActivity: Intent intent = getintent(); persons = (Persons)intent.getSerializableExtra("persons"); gdzie ważne jest, aby użyć tego samego klucza i odpowiedniego typu rzutowania. Zauważ też, że oncreate () określa, że pasek akcji dla okna powinien mieć przycisk Wstecz: getsupportactionbar (). setdisplayhomeasupenabled (true); i odpowiednie zastąpienie metody onsupportnavigationup (). Menu kontekstowe jest zdefiniowane jako zasób, a klasa musi implementować funkcję onconextitemselected (). Metoda ta dużo wypełnia, ale nie zawiera niczego nowego. Należy pamiętać, że tym razem przenosisz obiekt Person do działania DetailActivity. Nie chcę pokazywać kodu dla DetailActivity, ponieważ nie ma nic nowego. ĆWICZENIE 6: KSIĄŻKA Z NAZWISKAMI Powinieneś rozwinąć przykład NameBook, abyś mógł również zmienić informacje o kontakcie. Zacznij od kopii projektu NameBook. Musisz dodać nowe działanie do projektu, którego można użyć do edycji kontaktu. Pamiętaj, że to działanie powinno mieć układ podobny do MainActivity, z wyjątkiem tego, że nie możesz edytować nazwy i powinien istnieć tylko jeden przycisk. Nowe działanie należy otworzyć, rozszerzając menu kontekstowe o nowy element menu w ShowActivity. Ponadto klasa Osoby musi zostać rozszerzona o nową metodę, aby można było zaktualizować zmiany. Należy to zrobić w taki sam sposób, jak usunięcie, gdzie wszystkie aktywacje są zapisywane. Jest jedno wyzwanie, mianowicie kiedy zapisać zmiany. Najłatwiej jest to zrobić w ShowActivity, ale wymaga to, aby nowa aktywność mogła zwrócić wartość po kliknięciu przycisku Zapisz i zamknięciu okna. Powinieneś rozwiązać problem w ten sposób, zwłaszcza, że może być przydatny w innych kontekstach. Aby rozwiązać problem, wykonaj następujące kroki: W ShowActivity musisz dodać stałą (wartość nie jest ważna): private static final int PERSON_UPDATED = 1; Następnie musisz dodać następującą metodę: public void onactivityresult(int requestcode, int resultcode, Intent data) if (requestcode == PERSON_UPDATED)

84 if (resultcode == RESULT_OK) // here you can save the changes to the file Person person = (Person)data.getSerializableExtra("person"); Metoda onactivityresult() jest teraz metodą, którą można wywołać z nowej aktywności po jej zakończeniu i chce odesłać wartość z powrotem. Wymaga otwarcia nowej aktywności jako: startactivityforresult(intent, PERSON_UPDATED); W nowej aktywności możesz następnie napisać procedurę obsługi zdarzenia dla przycisku Zapisz w następujący sposób: public void onsave(view view) person.setphone(txtphone.gettext().tostring().trim()); person.setmail(txtmail.gettext().tostring().trim()); person.settext(txttext.gettext().tostring().trim()); Intent data = new Intent(); data.putextra("person", person); setresult(result_ok, data); finish(); PROBLEM 2: PUZZLEAPP Jako przykład fi w książce Java 4 pokazałem program, który symuluje prostą grę, która składa się z kwadratu 5 5 elementów ułożonych w losowej kolejności. Jeden z elementów jest pusty i możesz przenieść element, przesuwając sąsiada do pustego elementu. W poniższym przypadku (kwadrat po lewej) możesz następnie przesuwać elementy H, E, L i J (nie możesz poruszać się po przekątnej). Gra zostaje rozwiązana, gdy elementy są ułożone tak, jak pokazano w przykładzie po prawej stronie.

85 Kwadrat jest zasadniczo kwadratem 5 5, ale musi być tak samo jak w Javie 4 skonfigurować program, aby można było również grać z kwadratem 3 3, kwadratem 7 7 i 9 9 kwadrat. Ponadto program musi mieć listę najlepszych wyników, w której można zapisać pięć najlepszych wyników. Wynik składa się z liczby ruchów użytych do rozwiązania kwadratu, a zatem do rozwiązania kwadratu poprzez przesunięcie jak najmniejszej liczby pionków. Program powinien działać w taki sam sposób jak w Javie 4, ale tym razem musi zostać napisany na telefon komórkowy, a interfejs użytkownika może wyglądać następująco: Możesz ponownie użyć dużej części kodu z Java 4 - jeśli nie bezpośrednio, to używając mniejszych korekt. Oczywiście dwoma wyzwaniami jest interfejs użytkownika, który musi być napisany w inny sposób, i aby zapisać listę najlepszych wyników, którą należy zapisać w pliku lokalnym. 6 SQLITE Możesz także pisać aplikacje na telefony komórkowe korzystające z baz danych, ponieważ Android rodzi się z bardzo prostej bazy danych o nazwie SQLite. Baza danych jest również szeroko stosowana w wielu innych miejscach niż na urządzeniach z Androidem. Jest to prosta baza danych (co dokładnie jest również celem) i ma dalekie od wszystkich ułatwień, które udostępniają inne produkty bazodanowe (takie jak MySQL, Oracle itp.), Ale jest to kompletna baza danych SQL, w której można tworzyć lokalne bazy danych i wykonywać zwykłe operacje na bazie danych - prawie tak, jak znasz to z MySQL. W tym rozdziale pokażę ci, jak używać SQLite na przykładzie. Na przykład napiszę aplikację o nazwie PhoneBook, która odpowiada aplikacji Kontakt, z którą telefon się rodzi, ale nie jest ona

86 alternatywą dla tej aplikacji, ale służy jedynie do pokazania użycia bazy danych i powinna również być przykładem nieco większej aplikacji, a tym samym nieco bardziej realistycznej aplikacji niż to, co pokazały poprzednie przykłady. Dane aplikacji muszą być przechowywane w bazie danych z dwiema tabelami: gdzie jedna tabela jest tabelą z duńskimi kodami pocztowymi, a druga zawiera dane kontaktowe osób. Kod kolumny w adresach tabeli jest kluczem obcym do kodów pocztowych tabeli. Po otwarciu aplikacji pojawi się okno z przeglądem kodów pocztowych (patrz poniżej). U góry znajdują się dwa pola wprowadzania i dwa przyciski, które działają jak filtr kodów pocztowych. Zasadniczo kontakty są uporządkowane według kodów pocztowych. Aby znaleźć kontakt, przytrzymaj palec na kodzie pocztowym, po czym pojawi się menu kontekstowe, w którym możesz wyświetlić kontakty zorganizowane pod tym kodem pocztowym lub dodać nowy kontakt. Jeśli zdecydujesz się wyświetlić istniejące kontakty, istnieją trzy opcje: 1. Brak kontaktów, a otrzymasz prosty Toast, który ci powie. 2. Jest jeden kontakt, a program otwiera okno, w którym wyświetlane są informacje (patrz poniżej). W tym oknie możesz także edytować kontakt i go usunąć. 3. Pojawi się okno pokazujące wszystkie kontakty zorganizowane pod bieżącym kodem pocztowym. Nie pokazałem tutaj okna, ale jest to tylko ListView z nazwami tych kontaktów. Jeśli klikniesz tutaj nazwę, przejdziesz do okna ze wszystkimi informacjami kontaktowymi. Jako ostatnie dotyczące interfejsu użytkownika, MainActivity ma menu opcji z pojedynczą pozycją menu. Kliknięcie go powoduje otwarcie działania, w którym można wprowadzić kryteria wyszukiwania (imię, nazwisko, adres i tytuł), a program znajdzie kontakty spełniające kryteria wyszukiwania. Wynik ma te same trzy opcje, jak opisano powyżej.

87 To była funkcjonalność programu, a potem sposób pisania programu. Istnieją nie mniej niż 4 działania, ale żadne z nich nie zawiera niczego nowego, więc nie chcę wyświetlać kodu XML dla układu, a poniższe dotyczą tylko kodu Java i tutaj przede wszystkim jak 1. tworzy bazę danych 2. wykonuje WSTAWIENIE SQL 3. wykonuje aktualizację SQL 4. wykonuje DELETE SQL

88 5. wykonuje WYBÓR SQL a następujące zostaną skoncentrowane na tych 5 tematach. Program musi zostać zainicjowany przy użyciu duńskich kodów pocztowych, a dla ułatwienia dodałem zasób: raw / zipcodes.txt który jest plikiem oddzielonym przecinkami z duńskimi kodami pocztowymi. 6.1 TWORZY BAZĘ DANYCH Możesz utworzyć bazę danych na dwa sposoby. Możesz to zrobić na zewnątrz na komputerze programisty, a następnie skopiować bazę danych do aplikacji jako zasób, ale może to łatwo prowadzić do trudności, jeśli baza danych będzie musiała zostać zaktualizowana później. Z tego powodu istnieje klasa pomocnicza, która ułatwia utworzenie bazy danych w kodzie i zapewnia automatyczne tworzenie bazy danych przy pierwszym użyciu aplikacji, ale także zapewnia aktualizację bazy danych, jeśli zmienisz ją później - zakładając, że dodałeś wymagany kod. W niniejszej sprawie dodałem następującą klasę: package dk.data.torus.phonebook; import android.content.context; import android.database.sqlite.sqlitedatabase; import android.database.sqlite.sqliteopenhelper; java.io.*; public class DbHelper extends SQLiteOpenHelper public static final java.util.random rand = new java.util.random(); public static final String ZTABLE_NAME="zipcodes"; public static final int ZCOLNO_CODE = 0; public static final int ZCOLNO_CITY = 1; public static fi String[] ZTABLE_COLUMNS = new String[] "code", "city" public static final String ATABLE_NAME="addresses"; public static final int ACOLNO_ID = 0; public static final int ACOLNO_FIRRSTNAME = 1; public static final int ACOLNO_LASTNAME = 2; public static final int ACOLNO_ADDRESS = 3; public static final int ACOLNO_CODE = 4; public static final int ACOLNO_PHONE = 5;

89 public static final int ACOLNO_MAIL = 6; public static final int ACOLNO_DATE = 7; public static final int ACOLNO_TITLE = 8; public static final String[] ATABLE_COLUMNS = new String[] "id", "firstname", "lastname", "address", "code", "phone", "mail", "date", "title" ; private static final String DBFILENAME="phonebook.db"; private static final int DBVERSION = 1; private static final String ZINITIAL_SCHEMA = "create table zipcodes (code char(4) primary key, city varchar(30) not null)"; private static final String AINITIAL_SCHEMA = "create table addresses (" + "id integer primary key autoincrement," + "firstname varchar(50) not null," + "lastname varchar(30)," + "address varchar(50)," + "code char(4) not null," + "phone varchar(20)," + "mail varchar(50)," + "date varchar(10)," + "title varchar(50),"+ "foreign key (code) references zipcodes (code))"; private Context context; public DbHelper(Context context) super(context, DBFILENAME, null, DBVERSION); // super(context, DBFILENAME, null, rand.nextint(20) + 1); this.context = context; public void oncreate(sqlitedatabase db) db.execsql(zinitial_schema); db.execsql(ainitial_schema); db.execsql(insertzipcodes()); public void onupgrade(sqlitedatabase db, int oldversion, int newversion) // db.execsql("drop TABLE IF EXISTS zipcodes"); // db.execsql("drop TABLE IF EXISTS addresses");

90 // db.execsql(zinitial_schema); // db.execsql(ainitial_schema); // db.execsql(insertzipcodes()); public void ondowngrade(sqlitedatabase db, int oldversion, int newversion) // db.execsql("drop TABLE IF EXISTS zipcodes"); // db.execsql("drop TABLE IF EXISTS addresses"); // db.execsql(zinitial_schema); // db.execsql(ainitial_schema); // db.execsql(insertzipcodes()); private String insertzipcodes() InputStream stream = context.getresources(). openrawresource(r.raw.zipcodes); StringBuilder builder = new StringBuilder("insert into zipcodes (code, city) values "); try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) addrow(builder, reader.readline()); for (String line = reader.readline(); line!= null; line = reader.readline()) if (line.length() > 0) builder.append(","); addrow(builder, line);

91 catch (Exception e) return builder.tostring(); private void addrow(stringbuilder builder, String line) String[] elems = line.split(","); builder.append("('"); builder.append(elems[0]); builder.append("','"); builder.append(elems[1]); builder.append("')"); Początkowo zdefiniowano generator losowy i nie powinien on być częścią gotowej aplikacji, ale wyjaśnię za chwilę. W przeciwnym razie klasa definiuje dużą liczbę stałych, które definiują bazę danych. Te stałe nie są absolutnie konieczne, ale mogą ułatwić odczytanie i zrozumienie poniższego kodu oraz znacznie ułatwić jego utrzymanie. Dlatego wskazane jest wprowadzenie tych stałych, w tym przypadku istnieją dwa zestawy stałych dla każdej z dwóch tabel bazy danych. Kiedy zobaczysz stałe, łatwo jest zrozumieć znaczenie. Zauważ, że istnieje stała dla samej nazwy bazy danych, i pamiętaj, że istnieje stała dla numeru wersji. Zauważ również, że istnieją stałe dla dwóch wyrażeń SQL, które tworzą tabele bazy danych. Klasa dziedziczy SQLiteOpenHelper, a konstruktor w klasie podstawowej sprawdza, czy istnieje baza danych o tej nazwie. Jeśli nie, wykona oncreate (). Jeśli baza danych zostanie znaleziona, numer wersji jest testowany i jest większy niż numer wersji bazy danych, wykonywana jest metoda onupgrade (). Jest numerem wersji mniejszym niż numer wersji bazy danych, wykonywana jest metoda ondowngrade (). Klasa SQLiteOpenHelper powinna zatem zastąpić te trzy metody - jednak w wielu przypadkach nie zastępujesz ostatniej metody (numer wersji będzie zawsze wyższy). W takim przypadku oncreate () tworzy dwie tabele. Zauważ, że to konstruktor w klasie podstawowej tworzy bazę danych, podczas gdy oncreate () tworzy tabele. oncreate () wywołuje metodę insertzipcodes (). Używa StringBuilder do dynamicznego tworzenia SQL INSERT za pomocą zasobu z kodami pocztowymi, a metoda zwraca wynik jako ciąg. oncreate () ma parametr typu SQLiteDatabase i ma metody, takie jak nagłówek execsql(), który wykonuje instrukcję SQL. Metodę tę stosuje się do utworzenia dwóch tabel i ogólnie można jej użyć do wykonania instrukcji SQL reprezentowanej jako ciąg, a zatem również wyniku instrukcji insertzipcodes(). Program zastępuje również pozostałe dwie metody z klasy podstawowej: onupgrade() i ondowngrade(). Oba są trywialne, ponieważ cały kod został skomentowany, ale oznacza to, że musisz wstawić kod, który będzie używany, jeśli numer wersji zostanie zwiększony (dopóki nie zdefiniujesz ostatecznej wersji). Gdy tworzysz program, zazwyczaj będziesz zainteresowany tworzeniem bazy danych za każdym razem, gdy uruchamiasz program. Można to wymusić, zwiększając numer wersji, a następnie dodając kod do onupgrade (), który usuwa

92 istniejące tabele i tworzy je ponownie. Taki jest cel mojego generatora losowego, aby za każdym razem, gdy program był uruchamiany, otrzymywał losowy numer wersji (patrz konstruktor), w wyniku czego wykonywano onupgarde() lub ondownloa (). Oczywiście możesz pamiętać o usunięciu tej akcji przed zastosowaniem aplikacji, w przeciwnym razie usuniesz bazę danych za każdym razem, gdy aplikacja jest uruchomiona. 6.2 WYBÓR SQL Do projektu dodano dwie klasy modeli Kod pocztowy i Osoba, które reprezentują odpowiednio kod pocztowy i kontakt. Obie klasy są proste i składają się wyłącznie z metod get i set, ale należy pamiętać, że obie klasy są zdefiniowane jako Serializable, dzięki czemu obiekty klas można przenosić jako parametry do innych działań. Istnieje również klasa o nazwie Zipcodes, która reprezentuje wszystkie kody pocztowe: package dk.data.torus.phonebook; import android.database.cursor; import android.database.sqlite.sqlitedatabase; import java.util.arraylist; import java.util.list; public class Zipcodes implements java.io.serializable private List<Zipcode> zipcodes = new ArrayList(); public Zipcodes(SQLiteDatabase db) try Cursor cursor = db.query(dbhelper.ztable_name, DbHelper.ZTABLE_COLUMNS, null, null, null, null, null); for (cursor.movetofirst();!cursor.isafterlast(); cursor.movetonext()) String code = cursor.getstring(dbhelper.zcolno_code); String city = cursor.getstring(dbhelper.zcolno_city); zipcodes.add(new Zipcode(code, city)); cursor.close(); catch (Exception ex)

93 zipcodes.clear(); public List<Zipcode> getzipcodes() return zipcodes; Klasa ma zmienną pojedynczej instancji, która jest używana dla obiektów Zipcode. Lista jest inicjowana w konstruktorze, którego parametrem jest otwarta baza danych. Konstruktor zaczyna od utworzenia kursora, który jest obiektem reprezentującym WYBÓR SQL i może być używany do przechodzenia do wyniku. W takim przypadku instrukcja SELECT jest wykonywana przy użyciu metody query (), która jest dość złożoną metodą query(string table, String columns[], String selection, String selectionargs, String groupby, String having, String orderby, String limit) Metoda ma parametr dla każdego elementu, który może być zawarty w instrukcji SELECT, a powyżej mam tylko wartości dla pierwszych dwóch parametrów, ponieważ instrukcja powinna pobrać wszystkie kody pocztowe z bazy danych. Należy zwrócić uwagę na sposób definiowania nazwy tabeli i nazw kolumn za pomocą stałych w klasie DbHelper. Po zakończeniu instrukcji można przechodzić między wierszami za pomocą obiektu Cursor, obiektu, który zasadniczo działa w taki sam sposób jak zestaw wyników. Istnieje również klasa o nazwie Persons, która w zasadzie działa w ten sam sposób, ale zamiast tego konstruktor określa listę obiektów Person: package dk.data.torus.phonebook; import android.database.cursor; import android.database.sqlite.sqlitedatabase; import java.util.arraylist; import java.util.list; public class Persons implements java.io.serializable private List<Person> persons = new ArrayList();

94 public Persons(SQLiteDatabase db, Zipcode zipcode) try String[] params = new String[]zipcode.getCode(); Cursor cursor = db.rawquery("select * from addresses where code =?", params); for (cursor.movetofirst();!cursor.isafterlast(); cursor.movetonext()) int id = cursor.getint(dbhelper.acolno_id); String fname = cursor.getstring(dbhelper.acolno_firrstname); String lname = cursor.getstring(dbhelper.acolno_lastname); String addr = cursor.getstring(dbhelper.acolno_address); String phone = cursor.getstring(dbhelper.acolno_phone); String mail = cursor.getstring(dbhelper.acolno_mail); String date = cursor.getstring(dbhelper.acolno_date); String title = cursor.getstring(dbhelper.acolno_title); persons.add(new Person(id, fname, lname, addr, zipcode, phone, mail, date, title)); cursor.close(); catch (Exception ex) persons.clear(); public Persons(SQLiteDatabase db, String firstname, String lastname, String address, String persontitle) try Cursor cursor = db.query(dbhelper.atable_name, DbHelper.ATABLE_COLUMNS, "firstname like? and lastname like? and

95 address like? and title like?", new String[] firstname + "%", lastname + "%", "%" + address + "%", "%" + persontitle + "%", null, null, null); for (cursor.movetofirst();!cursor.isafterlast(); cursor.movetonext()) int id = cursor.getint(dbhelper.acolno_id); String fname = cursor.getstring(dbhelper.acolno_firrstname); persons.add(new Person(id, fname, lname, addr, getzipcode(db, code), phone, mail, date, title)); cursor.close(); catch (Exception ex) persons.clear(); public List<Person> getpersons() return persons; private Zipcode getzipcode(sqlitedatabase db, String code) Cursor cursor = db.query(dbhelper.ztable_name, DbHelper.ZTABLE_COLUMNS, "code =?", new String[] code, null, null, null); cursor.movetofirst(); return new Zipcode(cursor.getString(DbHelper.ZCOLNO_CODE), cursor.getstring(dbhelper.zcolno_city));

96 Oto najważniejsze: dwa konstruktory, które na podstawie kryteriów wyszukiwania określają liczbę kontaktów w bazie danych. Różnica polega na tym, jak definiują instrukcję SQL SELECT. Pierwszy wyszukuje wszystkie kontakty, które mają określony kod pocztowy, ale tym razem obiekt Cursor jest tworzony za pomocą metody rawquery (). Ma dwa parametry, z których pierwszy jest zwykłą instrukcją SELECT zapisaną jako ciąg. W taki sam sposób, jak widzieliśmy wcześniej, instrukcja SQL może mieć parametry wskazane przez? a ostatnim parametrem dla metody rawquery () powinna być tablica wartości, które należy zastąpić? symbole zastępcze. Po zakończeniu instrukcji Kursor używa obiektu w taki sam sposób jak powyżej, ale tym razem tworzone są obiekty Person. Zwróć uwagę, w jaki sposób poszczególne kolumny są powiązane ze stałymi z klasy DbHelper. Drugi konstruktor oprócz odwołania do otwartej bazy danych ma cztery parametry, z których wszystkie są łańcuchami. Konstruktor musi znaleźć wszystkie kontakty, w których imię zaczyna się od określonej wartości, gdzie nazwisko zaczyna się od określonej wartości, gdzie adres zawiera określoną wartość, a tytuł zawiera określoną wartość. Obiekt Cursor jest tym razem tworzony za pomocą metody query (), ale do zdefiniowania części WHERE służą cztery pierwsze parametry. Rzeczywista GDZIE jest ciągiem (wyrażeniem), a następujący parametr to tablica ciągów znaków zastępczych wyrażenia. W przeciwnym razie oba konstruktory wydają się działać identycznie, ale należy pamiętać, że w ostatnim przypadku konieczne jest określenie kodu pocztowego poprzez odczyt bazy danych. 6.3 WSTAWIANIE, AKTUALIZACJA I USUWANIE SQL Aplikacja ma działanie o nazwie PersonActivity, które służy do wyświetlania szczegółów kontaktu (patrz okno powyżej), ale także do tworzenia nowych kontaktów, edytowania istniejących kontaktów i usuwania kontaktów. Kod jest zatem podobnie kompleksowy: package dk.data.torus.phonebook; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.content.intent; import android.widget.*; import android.view.*; import android.database.sqlite.sqlitedatabase; import android.content.contentvalues; import java.util.*; public class PersonActivity extends AppCompatActivity private Zipcode zipcode = null; private Person person = null; private EditText txtzip;

97 private EditText txtfname; private EditText txtlname; private EditText txtaddr; private EditText txtphone; private EditText txtmail; private EditText txtdate; private EditText txttitle; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_person); Intent intent = getintent(); txtfname = (EditText) findviewbyid(r.id.txtfname); txtlname = (EditText) findviewbyid(r.id.txtlname); txtaddr = (EditText) findviewbyid(r.id.txtaddr); txtphone = (EditText) findviewbyid(r.id.txtphone); txtmail = (EditText) findviewbyid(r.id.txtmail); txtdate = (EditText) findviewbyid(r.id.txtdate txttitle = (EditText) findviewbyid(r.id.txttitle); txtzip = (EditText) findviewbyid(r.id.txtzip); Object obj = intent.getserializableextra("zipcode"); if (obj!= null) zipcode = (Zipcode) obj; Calendar cal = Calendar.getInstance(); txtdate.settext(string.format("%02d-%02d- %d", cal.get(calendar.day_of_month), cal.get(calendar.month) + 1, cal.get(calendar.year))); else person = (Person)intent.getSerializableExtra("person"); txtfname.settext(person.getfirstname());

98 txtlname.settext(person.getlastname()); txtaddr.settext(person.getaddress()); txtphone.settext(person.getphone()); txtmail.settext(person.getmail()); txtdate.settext(person.getdate()); txttitle.settext(person.gettitle()); zipcode = person.getzipcode(); getsupportactionbar().setdisplayhomeasupenabled(true); txtzip.settext(zipcode.tostring()); disable(txtdate); disable(txtzip); public boolean onsupportnavigateup() finish(); return true; public void onok(view view) String fname = txtfname.gettext().tostring().trim(); if (fname.length() > 0) String lname = txtlname.gettext().tostring().trim(); String addr = txtaddr.gettext().tostring().trim(); String phone = txtphone.gettext().tostring().trim(); String mail = txtmail.gettext().tostring().trim(); String date = txtdate.gettext().tostring().trim(); String title = txttitle.gettext().tostring().trim();

99 DbHelper dbhelper = new DbHelper(this); SQLiteDatabase db = dbhelper.getwritabledatabase(); ContentValues values = new ContentValues(8); values.put(dbhelper.atable_columns[dbhelper.acolno_firrstname], values.put(dbhelper.atable_columns[dbhelper.acolno_lastname], values.put(dbhelper.atable_columns[dbhelper.acolno_address], values.put(dbhelper.atable_columns[dbhelper. fname); lname); addr); ACOLNO_CODE], zipcode.getcode()); values.put(dbhelper.atable_columns[dbhelper.acolno_phone], phone); values.put(dbhelper.atable_columns[dbhelper.acolno_mail], mail); values.put(dbhelper.atable_columns[dbhelper.acolno_title], title); if (person == null) values.put(dbhelper.atable_columns[dbhelper.acolno_date], db.insert(dbhelper.atable_name, null, values); date); else Calendar cal = Calendar.getInstance(); values.put(dbhelper.atable_columns[dbhelper.acolno_date], String.format("%02d-%02d-%d", cal.get(calendar.day_of_month), cal.get(calendar.month) + 1, cal.get(calendar.year))); String[] args = "" + person.getid() ; db.update(dbhelper.atable_name, values, "id =?", args); db.close(); onsupportnavigateup(); public void onrem(view view) if (person!= null) DbHelper dbhelper = new DbHelper(this); SQLiteDatabase db = dbhelper.getwritabledatabase(); String[] args = "" + person.getid() ; db.delete(dbhelper.atable_name, "id =?", args); db.close(); onsupportnavigateup();

100 private void disable(edittext view) view.setkeylistener(null); view.setenabled(false); Klasa definiuje kilka zmiennych, ale ze względu na kod najważniejsze są dwie pierwsze, które definiują odpowiednio kod pocztowy i obiekt Person. Pozostałe zmienne są składnikami interfejsu użytkownika i są inicjowane w funkcji oncreate (). Po otwarciu odpowiedniego działania przekazywany jest parametr: obiekt Zipcode (jeśli chcesz utworzyć nowy kontakt) lub obiekt Person (jeśli chcesz wyświetlić lub edytować kontakt). Funkcja oncreate () rozpoczyna się od odwołania się do obiektu Zipcode, a jeśli to odwołanie nie ma wartości NULL, to jest to obiekt Zipcode, który został przesłany i zainicjalizowany jest zmienny kod pocztowy (podczas gdy zmienna osoba jest nadal pusta). Następnie pole txtdate jest ustawione na datę, ponieważ pole to musi zawierać datę ostatniej zmiany kontaktu. Jeśli obj wynosi zero, to dlatego, że przesłany parametr jest obiektem Person, a zmienna person jest następnie inicjowana tym obiektem. Jest to obiekt wyświetlany w interfejsie użytkownika, a wszystkie pola są inicjowane wartościami obiektu. Na koniec zauważ, że pola txtdate i txtzip są tylko do odczytu, ponieważ pól tych nie można zmienić. Klasa definiuje dwie procedury obsługi zdarzeń onok () i onrem (), gdzie pierwsza jest używana po kliknięciu przycisku OK, a ostatnia jest używana po kliknięciu przycisku USUŃ. onok () sprawdza, czy zostało wprowadzone imię (zakłada się, że kontakt musi mieć imię). Jeśli tak, program obsługi określa inne wartości wprowadzone w interfejsie użytkownika, a następnie tworzy obiekt reprezentujący bazę danych. Tutaj należy zwrócić uwagę na składnię, a baza danych może być zapisywana. Następnie tworzony jest obiekt ContentValue zawierający wartości, które mają zostać zapisane w bazie danych, bez względu na to, czy należy utworzyć nowy wiersz, czy też wiersz istniejący do zaktualizowania. Zwróć ponownie uwagę na składnię i zwróć uwagę na to, jak odwoływać się do poszczególnych kolumn za pomocą stałych zdefiniowanych w klasie DbHelper. Następnie zmienna osoba jest testowana, a jeśli jest pusta, jest to WSTAW, a w przeciwnym razie powinna być AKTUALIZACJA. Zasadniczo dzieje się to w ten sam sposób, w jednym przypadku używasz metody insert (), podczas gdy w drugim przypadku używasz metody update (), z tym wyjątkiem, że w tym drugim przypadku powinieneś podać GDZIE. Wreszcie istnieje ostatnia procedura obsługi zdarzeń używana do usunięcia kontaktu, a tym samym wykonania operacji SQL DELETE. Zasadniczo odbywa się to w taki sam sposób, jak powyżej, ale tam, gdzie musisz użyć metody delete (). 6.4 INNE DZIAŁANIA Aplikacja ma trzy dodatkowe działania. PersonsActivity wyświetla listę kontaktów znalezionych w bazie danych, i jest to proste działanie z ListVew, a kliknięcie kontaktu PersonActivity jest widoczne. Kod Java nie zawiera żadnych danych dotyczących baz danych. Działanie SearchActivity jest również proste i służy do wprowadzania kryteriów wyszukiwania, a kod jest wykonywany WYBIERANIE SQL, ale przy użyciu klasy Persons. Wreszcie istnieje funkcja MainActivity, która wiąże wszystko razem i wypełnia dużo. Nie chcę wyświetlać kodu dla tych trzech działań, ponieważ nie zawierają one niczego nowego dotyczącego baz danych, a przy okazji nic nowego. ZADANIE 7: KSIĄŻKA TELEFONICZNA

101 W tym ćwiczeniu będziesz musiał wprowadzić pewne zmiany do powyższego programu PhoneBook, a celem jest dodanie niewielkich ulepszeń, ale przede wszystkim trochę więcej pracy z programowaniem baz danych i SQLite. Zacznij od utworzenia kopii projektu. Jako pierwszą zmianę rozwiń adresy tabeli o dodatkową kolumnę, którą możesz nazwać tekstem i której typem powinno być VARCHAR (1000). Chodzi o to, aby krótki opis mógł być powiązany z kontaktem. Musisz zacząć zmieniać klasę DbHelper: 1. usuń zmienną rand na początku klasy 2. usuń wiersz z komentarzem w konstruktorze 3. usuń metodę ondowngrade () 4. dodaj do klasy stałą int o nazwie ACOLNO_TEXT i wartości 9 5. dodaj ciąg tekst do tablicy ATABLE_COLUMNS 6. zaktualizuj wyrażenie SQL (ciąg AINITIAL_SCEMA), tak aby tworzyło kolumnę z tekstem nazwy i typem varchar (1000). Następnie musisz zmienić metodę onupgrad() na następującą: public void onupgrade(sqlitedatabase db, int oldversion, int newversion) if (newversion > oldversion) try db.execsql("alter TABLE addresses ADD COLUMN text VARCHAR(1000) DEFAULT ''"); catch (Exception ex) Przetestuj program. Wynikiem powinno być teraz to, że adresy tabeli bazy danych mają nową kolumnę, ale nadal zawierają stare kontakty. Następnie należy rozwinąć program, tak aby można było również wprowadzić tekst, co oznacza, że okno do wprowadzania i edycji kontaktów musi zostać rozszerzone o pole wprowadzania:

102 Możesz wykonać następujące czynności: 1. Rozwiń klasę Osoba o dodatkową właściwość String, którą możesz nazwać tekstem. Konieczne jest także rozszerzenie dwóch konstruktorów o dodatkowy parametr dla nowej właściwości. 2. Osoby klasy muszą zostać zmienione, dlatego teraz bierze się pod uwagę, że tabela bazy danych ma nową kolumnę, a klasa Osoba nową właściwość. 3. Układ Activity_person.xml należy rozwinąć o nowe pole (i etykietę), które powinno być wielowierszowym tekstem edycji. 4. PersonActivity należy zaktualizować, aby wartość nowego pola była przechowywana w bazie danych. Przetestuj aplikację, aby upewnić się, że tekst został zapisany. Pamiętaj, aby przetestować zarówno tworzenie nowych kontaktów, jak i edytowanie istniejących kontaktów. Ponieważ program jest teraz napisany, wszystkie teksty są zakodowane na stałe, tj. Teksty etykiet, teksty przycisków, wiadomości toast i pozycje menu. Zamień te teksty na stałe w string.xml, jednocześnie definiując inne teksty dla 4 tytułów wiersza działania, abyś mógł zobaczyć, w której aplikacji pracujesz. Obecnie nie można zmienić kodu pocztowego. To chyba trochę zbyt restrykcyjne. Rozwiąż ten problem, gdy pole kodu pocztowego zawsze musi zawierać prawidłowy kod pocztowy. W aplikacji występuje inny problem, którego możesz nie wykryć przed zainstalowaniem aplikacji na urządzeniu fizycznym. Problem polega na tym, że działanie PersonActivity ma tak wiele pól, że są one objęte wirtualną klawiaturą. Możesz rozwiązać ten problem, umieszczając układ okna w ScrollView 7 WĄTKI

103 Android to wielowątkowy system operacyjny, więc możesz używać wątków prawie tak samo, jak znasz go z komputera. Po uruchomieniu aplikacji systemu Android system wykonawczy utworzy główny wątek, a wszystkie składniki aplikacji będą domyślnie działały w tym wątku. Głównym zadaniem głównego wątku jest obsługa interfejsu użytkownika, w tym przetwarzanie zdarzeń, ale wątek może oczywiście wykonać dowolną inną operację, w zależności od tego, która wartość jest domyślna. Podobnie jak to, co wiesz z komputera, wątek główny może rozpocząć wątek dodatkowy, i może istnieć wiele dobrych powodów, z których są takie same, jak wiesz wcześniej, ale istnieją również te same wyzwania, które jeśli wątek dodatkowy aktualizuje bezpośrednio użytkownika interfejs, więc program zatrzyma się z wyjątkiem. Jeśli używasz wątków, potrzebujesz trochę więcej, a celem tego rozdziału jest pokazanie, co jest potrzebne. Użyję przykładu, który użyłem wcześniej, czyli aplikacji, która otwiera następujące okno: W dwóch polach wejściowych możesz wprowadzić dwie dodatnie liczby całkowite i kliknąć OBLICZ, program określi wszystkie liczby pierwsze między dwoma wprowadzonymi liczbami i wstawi je do ListView pod przyciskami. Pomysł użycia liczb pierwszych polega na tym, że w przypadku dużych liczb ustalenie, czy liczba jest liczbą pierwszą, zajmuje dużo czasu, a jeśli wprowadzono tak duże liczby jak powyżej, w wyniku tego program sporadycznie dodaje liczbę pierwszą do składnika ListView. Aby ograniczyć zużycie pamięci, dwie wprowadzone liczby muszą różnić się tylko o 1000, ale możesz oczywiście zmienić, jeśli chcesz. Pod polami wprowadzania znajdują się trzy przyciski opcji. Jeśli wykonasz obliczenia i zostanie naciśnięty górny przycisk opcji, obliczenia zostaną wykonane w głównym wątku, co oznacza, że okaże się, że aplikacja nie odpowiada, a jeśli liczby są wystarczająco duże, otrzymasz ostrzeżenie, jak pokazano poniżej, gdzie możesz przerwać program:

104 Jeśli program może wykonywać obliczenia, to po znalezieniu wszystkich liczb pierwszych na pewno zaktualizuje składnik ListView o wszystkie znalezione liczby. Jeśli natomiast wykonasz program, gdy środkowy przycisk jest wciśnięty, obliczenia zostaną wykonane w drugim wątku, który aktualizuje składnik ListView za każdym razem, gdy zostanie znaleziona liczba pierwsza. Ponieważ nie zrobiono nic specjalnego, aby zaktualizować komponent, w rezultacie program zatrzymuje się z wyjątkiem. Z drugiej strony, jeśli program jest wykonywany przy wciśniętym dolnym przycisku opcji, uruchamia wszystko tak, jak powinno. Program aktualizuje komponent ListView i program żyje, ale tym razem bez powodowania problemów, jak to ma miejsce w przypadku obiektu Handler. Interfejs użytkownika składa się z 10 komponentów, które są umieszczone za pomocą RelativeLayout, a projekt nie zawiera niczego nowego, więc nie chcę tutaj wyświetlać kodu XML, więc tam, gdzie jest coś nowego, znajduje się w klasie MainActivity. Pełny kod wygląda następująco: package dk.data.torus.primesapp; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.*; import android.widget.*; import android.os.*; import android.content.*; import java.util.*;

105 public class MainActivity extends AppCompatActivity private EditText txtfrom; private EditText txtto; private RadioButton cmdprim; private RadioButton cmdsec1; private RadioButton cmdsec2; private ListView lstprimes; private ArrayAdapter<Long> adapter; private Handler messagehandler; private Handler primehandler; protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); txtfrom = (EditText) findviewbyid(r.id.txtfrom); txtto = (EditText) findviewbyid(r.id.txtto); cmdprim = (RadioButton) findviewbyid(r.id.cmdprim); cmdsec1 = (RadioButton) findviewbyid(r.id.cmdsec1); cmdsec2 = (RadioButton) findviewbyid(r.id.cmdsec2); lstprimes = (ListView) findviewbyid(r.id.lstprimes); lstprimes.setadapter(adapter = new ArrayAdapter<Long>(this, android.r.layout.simple_list_item_1, primes)); messagehandler = new MessageHandler(this); primehandler = new PrimeHandler(this, adapter); public void onclear(view view) adapter.clear();

106 public void oncalculate(view view) try long from = Long.parseLong(txtFrom.getText().toString()); long to = Long.parseLong(txtTo.getText().toString()); if (from > 0 && to > from && to from <= 1000) if (cmdprim.ischecked()) calc1(from, to); else if (cmdsec1.ischecked()) calc2(from, to); else calc3(from, to); return; catch (Exception ex) Toast.makeText(this, "Illegal values", Toast.LENGTH_LONG).show(); private void calc1(long a, long b) for (long t = a; t <= b; ++t) if (isprime(t)) adapter.add(t); private void calc2(long from, long to) final long a = from; final long b = to;

107 Runnable runnable = new Runnable() public void run() for (long t = a; t <= b; ++t) if (isprime(t)) adapter.add(t); ; (new Thread(runnable)).start(); private void calc3(long from, long to) final long a = from; final long b = to; Runnable runnable = new Runnable() public void run() for (long t = a; t <= b; ++t) if (isprime(t)) Message msg = primehandler.obtainmessage(); Bundle bundle = new Bundle(); bundle.putlong("prime", t); msg.setdata(bundle); primehandler.sendmessage(msg); messagehandler.sendemptymessage(0); ; (new Thread(runnable)).start(); private boolean isprime(long n) if (n == 2 n == 3 n == 5 n == 7) return true; if (n < 11 n % 2 == 0) return false;

108 for (long t = 3, m = (long)math.sqrt(n) + 1; t <= m; t += 2) if (n % t == 0) return false; return true; Klasa kończy się metodą isprime (), która sprawdza, czy liczba jest liczbą pierwszą i jest dobrze znaną metodą, z której korzystałem wiele razy. Klasa definiuje nie mniej niż 10 zmiennych instancji. Pierwszy to odniesienia do komponentów w interfejsie użytkownika, a nazwy mówią, do czego służą. Następnie istnieje List <Long> dla zawartości komponentu ListView i powiązanego adaptera, a na końcu są dwie zmienne typu Handler, do których wrócę za chwilę. W oncreate () nie ma też nic nowego, oprócz dwóch ostatnich instrukcji, które tworzą obiekty dla dwóch zmiennych Handler (wyjaśnione poniżej). Program ma dwa moduły obsługi zdarzeń dla przycisków, pierwszy jest trywialny i nie robi nic poza usuwaniem zawartości komponentu ListView. Drugi to moduł obsługi zdarzenia dla przycisku OBLICZ, i nawet jeśli kod się zapełni, moduł obsługi jest wystarczająco prosty. Musi określić wartości dwóch liczb wprowadzonych do interfejsu użytkownika i sprawdzić, czy są one zgodne z prawem. Jeśli tak nie jest, pojawi się prosty Toast z komunikatem o błędzie. Czy wartości są legalne, procedura obsługi zdarzeń wywołuje jedną z metod 1. calc1 () 2. calc2 () 3. calc3 () w zależności od tego, który przycisk radiowy jest wciśnięty. Czy jest to górny przycisk opcji, wywoływana jest metoda calc1 () z dwiema liczbami jako parametrami, a metoda składa się z pętli, która aktualizowała składnik ListView o liczbach pierwszych określonych w bieżącym zakresie: for (long t = a; t <= b; ++t) if (isprime(t)) adapter.add(t); Ponieważ calc1 () jest powszechną metodą, jest wykonywana przez główny wątek, który w zasadzie jest wystarczający, ale metoda może zająć dużo czasu (dla dużych parametrów wejściowych) iw tym czasie program nie reaguje i możesz otrzymać ostrzeżenie, jak pokazano powyżej. Jeśli zamiast tego zostanie wykonana funkcja calc2 (), dzieje się to samo, ale tym razem w wątku wtórnym, w którym wątek wykonuje powyższą pętlę. Po znalezieniu liczby pierwszej wywoływana jest metoda add () adaptera, która z powodu powiązania danych zaktualizuje interfejs użytkownika, a jak to się dzieje z innego wątku, program zawiedzie i zatrzyma się z wyjątkiem. Ten problem został rozwiązany w funkcji calc3 (), która aktualizuje interfejs użytkownika za pomocą obiektu Handler, który jest obiektem wykonywanym w głównym wątku. Na końcu pliku MainActivity. java jest zdefiniowana dwie klasy: class MessageHandler extends Handler

109 private Context context; public MessageHandler(Context context) this.context = context; public void handlemessage(message msg) Toast.makeText(context, "Primes generated", Toast.LENGTH_LONG).show(); class PrimeHandler extends Handler private Context context; private ArrayAdapter<Long> adapter; public PrimeHandler(Context context, ArrayAdapter<Long> adapter) this.context = context; this.adapter = adapter; public void handlemessage(message msg) Bundle bundle = msg.getdata(); Long prime = bundle.getlong("prime"); adapter.add(prime); Obie klasy zastępują metodę handlemessage (), która jest metodą wywołania zwrotnego wykonywaną przez główny wątek, a różnica między dwiema klasami polega między innymi na tym, które parametry są przesyłane. W pierwszej klasie uchwytmessage () jest trywialny, ponieważ po prostu wykonuje Toast, ale w drugiej klasie parametr musi zostać przesłany. Dzieje się tak z obiektem pakietu, w tym

110 przypadku musi to być Długi, który jest liczbą pierwszą do dodania do komponentu ListView. W szczególności należy zauważyć, że parametr ma typ Wiadomość, a także zwrócić uwagę na składnię odnoszącą się do przesyłanej wartości. Po udostępnieniu tych dwóch typów modułów obsługi program może tworzyć zmienne instancji danych typów, co dzieje się w funkcji oncreate (). Następnie jest metoda calc3 (), która jest zasadniczo identyczna z calc2 () i wykonuje zadanie wyznaczania liczb pierwszych w wątku wtórnym, ale metoda run () jest nieco zmieniona: public void run() for (long t = a; t <= b; ++t) if (isprime(t)) Message msg = primehandler.obtainmessage(); Bundle bundle = new Bundle(); bundle.putlong("prime", t); msg.setdata(bundle); primehandler.sendmessage(msg); messagehandler.sendemptymessage(0); W pętli for obiekt primehandler służy do utworzenia obiektu Message. Ponadto obiekt pakietu jest inicjowany z bieżącą liczbą pierwszą, a ten obiekt pakietu jest połączony z obiektem Message. Następnie wywoływana jest metoda sendmessage () obiektu primehandler. Po zakończeniu pętli drugi obiekt procedury obsługi jest używany do wysyłania wiadomości, ale tutaj wywoływana jest metoda sendemptymessage (). 8 USŁUGI Usługa jest składnikiem wykonywanym w tle bez bezpośredniej interakcji z użytkownikiem, a usługa nie ma interfejsu użytkownika. Usługi są używane do wykonywania operacji specjalnych i często operacji, które zajmują dużo czasu. Na przykład może to być pobieranie pliku z Internetu, testowanie nowych danych i inne. Usługa jest wykonywana z wyższym priorytetem niż działania, dlatego istnieje mniejsze prawdopodobieństwo, że usługa zostanie przerwana przez system Android, jeśli nie będą dostępne wystarczające zasoby. Możliwe jest jednak świadczenie usługi o takim samym priorytecie jak działania na pierwszym planie, a jeśli tak, konieczne jest posiadanie widocznego wskazania, że usługa jest aktywna, co jest używane przez odtwarzacze wideo i muzyczne. Istnieją dwa główne rodzaje usług: 1. Usługa jest uruchamiana, gdy aplikacja (działanie) uruchamia ją przez wywołanie metody startservice (). Po uruchomieniu usługa może działać w tle przez czas nieokreślony, nawet jeśli aplikacja, która ją uruchomiła, zostanie zniszczona. Zazwyczaj uruchomiona usługa wykonuje pojedynczą operację (jako pobranie lub przesłanie pliku przez sieć) i nie zwraca wyniku dzwoniącemu. Po zakończeniu operacji usługa powinna się zatrzymać. 2. Usługa jest ograniczona, gdy komponent aplikacji wiąże się z nią przez wywołanie metody bindservice (). Usługa powiązana oferuje interfejs klient-serwer, który umożliwia komponentom

111 interakcję z usługą, wysyłanie żądań, uzyskiwanie wyników, a także między procesami. Usługa powiązana działa tylko tak długo, jak długo jest z nią powiązany inny komponent aplikacji. Wiele składników może połączyć się z usługą na raz, ale gdy wszystkie z nich się cofną, usługa zostanie zniszczona. Domyślnie usługa jest wykonywana w tym samym procesie co główny wątek aplikacji, ale jeśli jest to usługa uruchamiana przez aplikację, usługa ta zwykle wykonuje swoją pracę w wątku dodatkowym, a usługa zostanie zakończona za pomocą koniec drugiego wątku. Android wykonuje szereg wstępnie zdefiniowanych usług, które mogą być stosowane przez dowolną aplikację, jeśli jest to dozwolone. Korzystanie z tych usług zwykle odbywa się ze specjalną klasą Manager przy użyciu metody getsystemservice (), a klasa Context definiuje więcej stałych dla tych usług. Oprócz tych usług systemowych aplikacja może definiować i stosować nowe usługi, które zachowują się tak samo, jak usługi systemowe. Usługi niestandardowe można na ogół uruchamiać z innych komponentów Androida, to znaczy działań, odbiorników i innych usług. Cały okres istnienia usługi odbywa się między wywołaniem metody oncreate () a wywołaniem metody ondestroy (), gdzie oncreate () jest używany do wszystkich początkowych ustawień, podczas gdy uwalnianie zasobów odbywa się w ondestroy (). Metody są wywoływane dla wszystkich usług, niezależnie od tego, czy są tworzone przez startservice () czy bindservice (). Usługa rozpoczyna swoją pracę od wywołania funkcji onstartcommand () lub onbind (). Każda metoda otrzymuje obiekt Intent przekazywany odpowiednio do startservice () lub bindservice (). Jeśli usługa jest uruchomiona, kończy działanie po powrocie onstartcommand (), a jeśli usługa jest powiązana, kończy się, gdy wraca onunbind (). Usługa musi być zdefiniowana w AndroidManifest.xml i napisana jako klasa, która dziedziczy klasę Usługa lub jedna z jej podklas. Na przykład składnik systemu Android (i jak dotąd, mówiąc o działaniu) może uruchomić usługę za pomocą metody startservice (), a alternatywnie może użyć bindservice (), która umożliwia bezpośrednią komunikację z usługą. Uruchomiona usługa rozpoczyna życie od metody startservice (), a jeśli usługa jeszcze nie działa, obiekt usługi jest tworzony w metodzie oncreate () usługi. Po uruchomieniu usługa może powiadamiać użytkownika o zdarzeniach za pomocą powiadomień Toast lub powiadomień na pasku stanu, ale usługa nie może bezpośrednio zadzwonić do użytkownika. Metoda onstartcommand () zwraca wartość int wskazującą, w jaki sposób usługi powinny zostać zrestartowane, jeśli zostanie ono zakończone przez system Android i dostępne są następujące opcje: 1. Service.START_STICKY, co oznacza, że usługa jest restartowana, ale w taki sposób, że obiekt Intent jest pusty i używany, jeśli usługa zachowuje swój własny stan i nie zależy od obiektu Intent. 2. Service.START_NOT_STICKY, co oznacza, że usługa nie zostanie automatycznie uruchomiona ponownie. 3. Service.START_REDELIVER_INTENT, co oznacza to samo co pierwsza opcja, ale z tą różnicą, że oryginalny obiekt Intent jest wysyłany do onstartcommand(). Można zakończyć usługę za pomocą metody stopservice (), a usługa może zakończyć się za pomocą stopself (). Aby utworzyć powiązaną usługę, należy zaimplementować metodę onbind (), która zwraca IBinder definiujący interfejs do komunikacji z usługą. Inne aplikacje mogą następnie wywołać bindservice () w celu pobrania interfejsu i rozpoczęcia wywoływania metod w usłudze. Usługa jest dostępna tylko wtedy, gdy istnieją związane z nią aplikacje, a gdy nie ma żadnych składników powiązanych z usługą, system ją niszczy i nie trzeba zatrzymywać usługi powiązanej w sposób, w jaki należy to zrobić, gdy usługa jest uruchamiany za pomocą onstartcommand (). Istnieją dwa sposoby zdefiniowania interfejsu IBinder:

112 1. Rozszerzanie klasy Binder. Jeśli twoja usługa jest prywatna dla twojej aplikacji i działa w tym samym procesie co aplikacja, co często ma miejsce, powinieneś stworzyć swój interfejs, rozszerzając klasę Binder i zwracając jej instancję z onbind (). Następnie klient otrzymuje obiekt Binder i może go użyć do bezpośredniego dostępu do metod publicznych dostępnych w implementacji Binder lub w usłudze. Gdy usługa jest jedynie tłem roboczym dla aplikacji, jest to sposób na utworzenie Binder, a jedynym powodem, dla którego nie należy tworzyć interfejsu w ten sposób, jest to, że z usługi muszą korzystać inne aplikacje lub oddzielne procesy. 2. Korzystanie z komunikatora. Jeśli twój interfejs musi działać w różnych procesach, możesz utworzyć interfejs dla usługi za pomocą Messengera. W ten sposób usługa definiuje moduł obsługi, który reaguje na różne typy obiektów Message. Ten moduł obsługi jest podstawą komunikatora, który może udostępniać IBinder klientowi, umożliwiając klientowi wysyłanie poleceń do usługi przy użyciu obiektów wiadomości. Klient może również zdefiniować własnego komunikatora, aby usługa mogła wysyłać wiadomości z powrotem. Jest to najprostszy sposób na komunikację międzyprocesową, ponieważ Messenger kolejkuje wszystkie żądania w jednym wątku, dzięki czemu nie musisz projektować usługi tak, aby była bezpieczna dla wątków. Składniki aplikacji mogą łączyć się z usługą, wywołując bindservice (), a następnie Android wywołuje metodę onbind () usługi, która zwraca obiekt IBinder do interakcji z usługą. Zdarza się to asynchronicznie, a funkcja bindservice () zwraca natychmiast i nie zwraca obiektu IBinder. Aby otrzymać obiekt, klient musi utworzyć instancję ServiceConnection i przekazać ją do bindservice (). ServiceConnection to interfejs definiujący metodę onserviceconnected (), którą system wywołuje w celu uzyskania obiektu IBinder. Interfejs definiuje również metodę onservicedisconnected (), którą Android wywołuje, gdy połączenie z usługą zostanie utracone, ponieważ usługa uległa awarii lub została zabita. Metoda nie jest wywoływana, gdy aplikacja rozpina się. Aby rozłączyć się z usługą, musisz wywołać metodę unbindservice (). Gdy aplikacja zostanie zniszczona, automatycznie usunie powiązanie z usługą, ale zawsze powinieneś cofnąć wiązanie po zakończeniu, aby usługa mogła zostać zamknięta, gdy nie jest już używana. Usługa może być również usługą pierwszego planu, która jest usługą powiązaną z czymś, o czym użytkownik jest świadomy, a zatem nie jest kandydatem do zabicia systemu, gdy brakuje mu pamięci. Usługa pierwszego planu musi dostarczyć powiadomienie na pasku stanu, które jest powiadomieniem, którego nie można zamknąć, chyba że usługa zostanie zatrzymana lub usunięta z pierwszego planu. Aby uruchomić usługę na pierwszym planie, należy użyć metody startforeground (), która przyjmuje dwa parametry, przy czym pierwszy jest liczbą całkowitą, która jednoznacznie identyfikuje powiadomienie i powiadomienie dla paska stanu. W prostym przypadku nie ma potrzeby jakiejkolwiek komunikacji między działalnością a usługą. Usługa odbiera obiekt Intent z komponentu działania, a następnie usługa wykonuje swoją pracę, ale w innych kontekstach istnieje potrzeba bezpośredniej komunikacji między działaniem a usługą, a tutaj można użyć odbiornika. Aktywność może wykryć odbiornik rozgłoszeniowy dla zdarzenia, a usługa może wysyłać powiadomienia o tym zdarzeniu i zazwyczaj odpowiada, że usługa zasygnalizuje obiektowi aktywności, że zakończyła pracę: Odbiornik rozgłoszeniowy to klasa, która rozszerza BroadcastReceiver i która jest zarejestrowana jako odbiornik w aplikacji innej niż AndroidManifest.xml lub w kodzie. Odbiornik będzie mógł odbierać

113 zamiary wygenerowane za pomocą metody Context.sendBroadcast (). Klasa BroadcastReceiver definiuje metodę onreceive (), której aplikacja może użyć do uzyskania otrzymanego obiektu. Krótko opowiedziałem trochę o teorii, a poniżej pokażę, co dokładnie należy napisać, aby korzystać z usług, przynajmniej początek prostych usług i korzystanie z usług lokalnych, ale temat jest w rzeczywistości stosunkowo złożony, i ja wróć do niego w następnej książce. W tej książce nie ma między innymi obiektów BroadcastReceiver. Najpierw jednak chciałbym załączyć kilka uwag do klasy Intent. 8.1 KLASA INTENT Klasa Intent nie ma wyłącznie związku z usługami, i korzystałem już z niej wiele razy, nie wspominając o tym, co to jest dla klasy. Ponieważ klasa odgrywa kluczową rolę w usługach, krótko o tym wspomnę. Klasa dotyczy przede wszystkim czynności, usług i odbiorników telewizyjnych. Te komponenty są tworzone za pomocą komunikatów zwanych intencjami, które są formą późnego wiązania komponentów, więc zawsze dzieje się tak samo. Obiekt Intent to struktura danych, która zawiera abstrakcyjny opis operacji do wykonania lub opis czegoś, co się wydarzyło i musi zostać zareklamowane. Istnieje kilka mechanizmów wysyłania zamiarów do różnych typów komponentów: 1. Obiekt Intent można przekazać do Context.startActivity () lub Activity.startActivityForResult () w celu uruchomienia działania lub uzyskania istniejącego działania w celu wykonania czegoś nowego. Można go również przekazać do Activity.setResult (), aby zwrócić informacje z działania wykonanego za pomocą startactivityforresult (). 2. Obiekt Intent można przekazać do Context.startService () w celu zainicjowania usługi lub dostarczenia nowych instrukcji do uruchomionej usługi. Podobnie, zamiar można przekazać do kontekstu. bindservice () w celu ustanowienia połączenia między działaniem wywołującym a usługą. Można go również użyć do zainicjowania usługi, jeśli jeszcze nie jest uruchomiona. 3. Obiekty intencyjne mogą być przekazywane do metod rozgłaszania (patrz następna książka), takich jak Kontekst. sendbroadcast (), Context.sendOrdersBroadcast () lub Context.sendStickyBroadcast () i są dostarczane do wszystkich zainteresowanych odbiorców. Intencje są bardzo przydatne w przypadku usług do wymiany informacji i powiadomień między obiektem wywołującym a usługą. Zachęcamy do zapoznania się z dokumentacją dla klasy Intent. 8.2 SERVICEAPP1 Usługa jest zapisywana jako klasa dziedzicząca klasę Service lub IntentService, gdzie ostatnia pochodzi od pierwszej. Celem usługi IntentService jest maksymalne uproszczenie uruchomienia usługi. Usługa realizuje żądania asynchronicznie we własnym wątku i może to zająć tak długo, jak to konieczne i nie blokuje aplikacji. Indywidualne żądanie jest dodawane do kolejki i wykonywane pojedynczo. Usługa IntentService to usługa w tle, która jest uruchamiana przez działanie, a następnie nie ma bezpośredniej komunikacji między usługą a działaniem. Typowa aplikacja to rozpoczęcie działania, które zajmuje dużo czasu, np. Pobranie pliku. Przykładowa ServiceApp1 otwiera następujące okno:

114 Jeśli klikniesz górny przycisk, okno otrzyma losowy kolor, a kliknięcie dolnego przycisku uruchamia usługę IntentService. Usługa jest napisana jako następująca klasa: import android.app.intentservice; import android.content.intent; import android.net.uri; import android.media.ringtonemanager; import android.media.ringtone; public class TheService extends IntentService public TheService() super("theservice"); protected void onhandleintent(intent intent) long n = intent.getlongextra("todo", 0);

115 for (long i = 0; i < n; ++i) Math.sin(Math.sqrt(i)); Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification); r.play(); Klasa powinna mieć tylko domyślnego konstruktora, który wykonuje konstruktor klasy podstawowej z nazwą usługi jako parametrem, a ponadto musi zastąpić metodę onhandleintent (), która jest metodą, która wykonuje pożądaną akcję. W takim przypadku metoda wykonuje długą (bezsensowną) akcję, po której aktywuje dzwonek. W odniesieniu do akcji, celem jest pokazanie, w jaki sposób z intencją możesz przenieść wartości do usługi i że usługa robi coś przez chwilę, zanim z powodu dźwięku zauważy, że usługa wykonała swoją pracę. Gdy aplikacja korzysta z usługi, musi być zdefiniowana w manifeście programu <application </activity> <service android:name=".theservice" /> </application> Szczegół, który należy pamiętać. W odniesieniu do programu (MainActivity), celem przycisku górnego jest pokazanie, że aplikacja nie jest blokowana, gdy usługa wykonuje swoją pracę - a także trochę pokazanie, jak zmienić kolor tła okna. Podczas wypróbowywania programu pamiętaj, że możesz uruchomić wiele usług i sposób ich umieszczenia w kolejce. Kod dla MainActivity jest następujący: package serviceapp1.dk.data.torus.serviceapp1; import android.graphics.color; import android.support.v7.app.appcompatactivity; import android.os.bundle; import android.view.*; import android.content.*; import java.util.random; public class MainActivity extends AppCompatActivity private static Random rand = new Random();

116 protected void oncreate(bundle savedinstancestate) super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); public void onclick(view view) getwindow().getdecorview().setbackgroundcolor(getcolor()); public void onstart(view view) Intent intent = new Intent(this, TheService.class); intent.putextra("todo", L); startservice(intent); private int getcolor() return Color.rgb(rand.nextInt(256), rand.nextint(256), rand.nextint(256)); Najważniejsza jest tutaj funkcja obsługi zdarzeń onstart (), która uruchamia usługę. Po pierwsze, zamiar obiekt jest tworzony dla usługi, a usługa jest uruchamiana za pomocą metody startservice (). 8.3 SERVICEAPP2 Często usługa IntentService nie zapewnia wystarczających opcji, na przykład jeśli chcesz zatrzymać działającą usługę, a następnie będziesz musiał napisać usługę, która bezpośrednio odziedziczy klasę. Program ServiceApp2 pokazuje jak. Okno programu jest prawie identyczne z powyższym, tylko jest trzeci przycisk:

117 który służy do zatrzymania uruchomionej usługi. Usługa jest tym razem napisana jako: package serviceapp2.dk.data.torus.serviceapp2; import android.app.service; import android.content.intent; import android.os.ibinder; import android.widget.toast; public class TheService extends Service public void oncreate() Toast.makeText(this, "Service created", Toast.LENGTH_LONG).show(); public IBinder onbind(intent arg0) return null;

Podstawowe elementy GUI - zadania

Podstawowe elementy GUI - zadania Podstawowe elementy GUI - zadania LIVE DEMO Proszę stworzyć prostą aplikację do obliczania pól figur geometrycznych. To add images to the drawable forlder, right click on it, and select the Show in Explorer

Bardziej szczegółowo

Programowanie urządzeń mobilnych w systemie Android. Ćwiczenie 7 Wykorzystanie układu LinearLayout

Programowanie urządzeń mobilnych w systemie Android. Ćwiczenie 7 Wykorzystanie układu LinearLayout Ćwiczenie 7 Wykorzystanie układu LinearLayout Cel ćwiczenia Celem ćwiczenia jest praktyczne zapoznanie się z zasadami użycia układu graficznego LinearLayout oraz wykształcenie umiejętności zastosowania

Bardziej szczegółowo

Programowanie urządzeń mobilnych w systemie Android. Ćwiczenie 8 Wykorzystanie układu RelativeLayout

Programowanie urządzeń mobilnych w systemie Android. Ćwiczenie 8 Wykorzystanie układu RelativeLayout Ćwiczenie 8 Wykorzystanie układu RelativeLayout Cel ćwiczenia Celem ćwiczenia jest praktyczne zapoznanie się z zasadami użycia układu graficznego RelativeLayout oraz wykształcenie umiejętności zastosowania

Bardziej szczegółowo

Aktywności są związane z ekranem i definiują jego wygląd. Dzieje się to poprzez podpięcie do aktywności odpowiedniego widoku.

Aktywności są związane z ekranem i definiują jego wygląd. Dzieje się to poprzez podpięcie do aktywności odpowiedniego widoku. Aktywności to podstawowe elementy związane z platformą Android. Dzięki poznaniu aktywności będziesz w stanie napisać pierwszą aplikację przeznaczoną na urządzenie mobilne. Po dodaniu kontrolek możesz w

Bardziej szczegółowo

[Android] Podstawy programowania

[Android] Podstawy programowania Page 1 of 7 [Android] Podstawy programowania LinkiPrzewodnik z przykładamizasosbykrótka prezentacja wprowadzająca do budowy systemuprosta aplikacja z menu i dialogami, którą utworzymy tutaj krok po kroku

Bardziej szczegółowo

Programowanie urządzeń mobilnych. dr inż. Juliusz Mikoda

Programowanie urządzeń mobilnych. dr inż. Juliusz Mikoda Programowanie urządzeń mobilnych dr inż. Juliusz Mikoda Instalacja środowiska 1 Wymagane składniki środowiska Eclipse wersja 3.4 (Ganymede) lub 3.5 (Galileo classic) http://www.eclipse.org/downloads/packages/release/galileo/r

Bardziej szczegółowo

Android pierwsza aplikacja

Android pierwsza aplikacja Android pierwsza aplikacja I. Środowisko 1. Uruchomić środowisko Android Devloppers tools 2. Wybrać/Utworzyć Wokspace Mobile-cw2 II Projekt 1. Utworzyć nowy projekt klikając na w pasku narzędzi 2. Rozwinąć

Bardziej szczegółowo

Laboratorium Systemów Mobilnych. Wykład 1

Laboratorium Systemów Mobilnych. Wykład 1 Laboratorium Systemów Mobilnych 2015-02-27 Wykład 1 (Wstęp do programowania w systemie Android) Wojciech Wawrzyniak Zaliczenie wykładu i ćwiczeń Wykład omówienie zagadnień Ćwiczenie praktyczne zastosowanie

Bardziej szczegółowo

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem. WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM NetBeans Wykonał: Jacek Ventzke informatyka sem. VI 1. Uruchamiamy program NetBeans (tu wersja 6.8 ) 2. Tworzymy

Bardziej szczegółowo

AndroidManifest.xml. Plik manifestu opisuje podstawowe charakterystyki aplikacji i definiuje jej komponenty.

AndroidManifest.xml. Plik manifestu opisuje podstawowe charakterystyki aplikacji i definiuje jej komponenty. AndroidManifest.xml Plik manifestu opisuje podstawowe charakterystyki aplikacji i definiuje jej komponenty. Jednym z najważniejszych elementów jest element który deklaruje kompatybilność z innymi

Bardziej szczegółowo

Laboratorium 8 ( Android -pierwsza aplikacja)

Laboratorium 8 ( Android -pierwsza aplikacja) Dr Mirosław Łątka Informatyka dla medycyny Jesień 2012 Laboratorium 8 ( Android -pierwsza aplikacja) Naszym celem jest stworzenie aplikacji, która wyświetla zdjęcie Alberta Einsteina. Jeden z przycisków

Bardziej szczegółowo

1. Dockbar, CMS + wyszukiwarka aplikacji Dodawanie portletów Widok zawartości stron... 3

1. Dockbar, CMS + wyszukiwarka aplikacji Dodawanie portletów Widok zawartości stron... 3 DODAJEMY TREŚĆ DO STRONY 1. Dockbar, CMS + wyszukiwarka aplikacji... 2 2. Dodawanie portletów... 3 Widok zawartości stron... 3 Omówienie zawartości portletu (usunięcie ramki itd.)... 4 3. Ikonki wybierz

Bardziej szczegółowo

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2.

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2. Spis treści: 1 Podstawy pracy z aplikacją... 2 1.1 Układ strony... 2 strona 1 z 7 1 Podstawy pracy z aplikacją InDesign jest następcą starzejącego się PageMakera. Pod wieloma względami jest do niego bardzo

Bardziej szczegółowo

Tworzenie wydajnych interfejsów. Autorzy: Piotr Michałkiewicz, 2 rok AiR Daniel Maksymow, 2 rok Informatyki

Tworzenie wydajnych interfejsów. Autorzy: Piotr Michałkiewicz, 2 rok AiR Daniel Maksymow, 2 rok Informatyki Tworzenie wydajnych interfejsów Autorzy: Piotr Michałkiewicz, 2 rok AiR Daniel Maksymow, 2 rok Informatyki Wstęp Tematem dzisiejszych zajęć będą: - Layouty - FrameLayout - LinearLayout - RelativeLayout

Bardziej szczegółowo

Podstawy technologii WWW

Podstawy technologii WWW Podstawy technologii WWW Ćwiczenie 8 PHP, czyli poczatki nowej, dynamicznej znajomosci Na dzisiejszych zajęciach rozpoczniemy programowanie po stronie serwera w języku PHP. Po otrzymaniu żądania serwer

Bardziej szczegółowo

Praca z wynikami w ALOORA

Praca z wynikami w ALOORA AGROLAB GROUP 02-2018 1 / 15 Spis treści Rozdział 1: praca z dwoma widokami wyników... 3 Wyniki według zlecenia... 3 Wyniki według próbki... 3 Modyfikowanie widoków... 3 Wybieranie określonych zleceń lub

Bardziej szczegółowo

DODAJEMY TREŚĆ DO STRONY

DODAJEMY TREŚĆ DO STRONY DODAJEMY TREŚĆ DO STRONY SPIS TREŚCI Pasek narzędzi i wyszukiwarka aplikacji... 2 Dodawanie portletów... 3 Widok zawartości stron... 4 Zawartość portletu... 5 Ikonki wybierz oraz dodaj zawartość stron...

Bardziej szczegółowo

Wstawianie nowej strony

Wstawianie nowej strony Wstawianie nowej strony W obszernych dokumentach będziemy spotykali się z potrzebą dzielenia dokumentu na części. Czynność tę wykorzystujemy np.. do rozpoczęcia pisania nowego rozdziału na kolejnej stronie.

Bardziej szczegółowo

Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod:

Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod: 1. Listener dla przycisku. Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod: W linii 24 tworzymy globalną metodę mglobal_onclicklistener,

Bardziej szczegółowo

Uruchamianie bazy PostgreSQL

Uruchamianie bazy PostgreSQL Uruchamianie bazy PostgreSQL PostgreSQL i PostGIS Ten przewodnik może zostać pobrany jako PostgreSQL_pl.odt lub PostgreSQL_pl.pdf Przejrzano 10.09.2016 W tym rozdziale zobaczymy, jak uruchomić PostgreSQL

Bardziej szczegółowo

2018/10/16 20:47 1/5 3 Ekrany

2018/10/16 20:47 1/5 3 Ekrany 2018/10/16 20:47 1/5 3 Ekrany 3 Ekrany Przegląd W ekranach Zabbix można grupować informacje z różnych źródeł, co pozwala na szybki przegląd na jednym ekranie. Budowanie ekranu jest całkiem proste i intuicyjne.

Bardziej szczegółowo

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia nowego projektu (poniżej są utworzone projekty) Po kliknięciu

Bardziej szczegółowo

uczyć się bez zagłębiania się w formalnym otoczeniu,

uczyć się bez zagłębiania się w formalnym otoczeniu, CZĘŚĆ 3 - INTERNET 3.1 WSTĘP Internet jest globalnym zbiorem połączonych ze sobą komputerów, które przesyłają informacje między sobą za pośrednictwem szybkich połączeń sieciowych oraz linii telefonicznych.

Bardziej szczegółowo

Przewodnik... Tworzenie Landing Page

Przewodnik... Tworzenie Landing Page Przewodnik... Tworzenie Landing Page Spis treści Kreator strony landing page Stwórz stronę Zarządzaj stronami 2 Kreator strony landing page Kreator pozwala stworzyć własną stronę internetową z unikalnym

Bardziej szczegółowo

Powiadomienia w systemie Android

Powiadomienia w systemie Android Powiadomienia w systemie Android Powiadomienie to krótka wiadomość, która pozwala informować użytkownika o pewnych wydarzeniach pochodzących z aplikacji - będąc poza nią. Wykorzystane w odpowiedni sposób

Bardziej szczegółowo

Informatyka II. Laboratorium Aplikacja okienkowa

Informatyka II. Laboratorium Aplikacja okienkowa Informatyka II Laboratorium Aplikacja okienkowa Założenia Program będzie obliczał obwód oraz pole trójkąta na podstawie podanych zmiennych. Użytkownik będzie poproszony o podanie długości boków trójkąta.

Bardziej szczegółowo

Przewodnik Szybki start

Przewodnik Szybki start Przewodnik Szybki start Program Microsoft Word 2013 wygląda inaczej niż wcześniejsze wersje, dlatego przygotowaliśmy ten przewodnik, aby skrócić czas nauki jego obsługi. Pasek narzędzi Szybki dostęp Te

Bardziej szczegółowo

WAŻNE! colour.me Google Fonts tutaj

WAŻNE! colour.me Google Fonts tutaj Otwieramy dokument, ustalamy podstawowe parametry. 1. Wpisujemy liczbę stron w tym przypadku będą to 2 (przód i tył). 2. Ustalamy rozmiar docelowy w tym przypadku 85x55 mm. 3. Odznaczamy opcję: strony

Bardziej szczegółowo

Aplikacje mobilne. Pliki zasobów, grafiki, menu, podpinanie zdarzeń. dr Tomasz Jach Instytut Informatyki, Uniwersytet Śląski

Aplikacje mobilne. Pliki zasobów, grafiki, menu, podpinanie zdarzeń. dr Tomasz Jach Instytut Informatyki, Uniwersytet Śląski Aplikacje mobilne Pliki zasobów, grafiki, menu, podpinanie zdarzeń dr Tomasz Jach Instytut Informatyki, Uniwersytet Śląski Pliki zasobów Jak już robiliśmy wcześniej sporo rzeczy w Androidzie umieszczamy

Bardziej szczegółowo

ROZDZIAŁ 1. PRZEGLĄD BRAMOFONU SAFE...

ROZDZIAŁ 1. PRZEGLĄD BRAMOFONU SAFE... Spis treści INSTRUKCJA OBSŁUGI SPIS TREŚCI ROZDZIAŁ 1. PRZEGLĄD BRAMOFONU SAFE... 2 1.3. WYMAGANIA SYSTEMU... 2 ROZDZIAŁ 2. APLIKACJA I URZĄDZENIE.... 4 2.1. DODAWANIE BRAMOFONU DO APLIKACJI... 4 2.2.

Bardziej szczegółowo

Czym jest MIT App Inventor. App Inventor jest to zbiór bloków jako język programowania używany do tworzenia mobilnych aplikacji na androida.

Czym jest MIT App Inventor. App Inventor jest to zbiór bloków jako język programowania używany do tworzenia mobilnych aplikacji na androida. App Inventor Czym jest MIT App Inventor App Inventor jest to zbiór bloków jako język programowania używany do tworzenia mobilnych aplikacji na androida. MIT App Inventor Gdzie tworzysz interfejs użytkownika

Bardziej szczegółowo

System Obsługi Zleceń

System Obsługi Zleceń System Obsługi Zleceń Podręcznik Administratora Atinea Sp. z o.o., ul. Chmielna 5/7, 00-021 Warszawa NIP 521-35-01-160, REGON 141568323, KRS 0000315398 Kapitał zakładowy: 51.000,00zł www.atinea.pl wersja

Bardziej szczegółowo

BAZY DANYCH Panel sterujący

BAZY DANYCH Panel sterujący BAZY DANYCH Panel sterujący Panel sterujący pełni z reguły rolę centrum, z którego wydajemy polecenia i uruchamiamy różnorodne, wcześniej zdefiniowane zadania, np. wyświetlamy formularze lub drukujemy

Bardziej szczegółowo

BIBLIOTEKA LOKALNE CENTRUM WIEDZY PRAKTYCZNEJ PRZEWODNIK PO NARZĘDZIACH WARSZTAT NR 1: ARKUSZE KALKULACYJNE - MINI SKRYPT

BIBLIOTEKA LOKALNE CENTRUM WIEDZY PRAKTYCZNEJ PRZEWODNIK PO NARZĘDZIACH WARSZTAT NR 1: ARKUSZE KALKULACYJNE - MINI SKRYPT BIBLIOTEKA LOKALNE CENTRUM WIEDZY PRAKTYCZNEJ PRZEWODNIK PO NARZĘDZIACH WARSZTAT NR 1: ARKUSZE KALKULACYJNE - MINI SKRYPT 1. Wprowadzenie Arkusze kalkulacyjne Google umożliwiają łatwe tworzenie, udostępnianie

Bardziej szczegółowo

Programowanie urządzeń mobilnych. dr inż. Andrzej Grosser na podstawie wykładu dr inż. Juliusza Mikody

Programowanie urządzeń mobilnych. dr inż. Andrzej Grosser na podstawie wykładu dr inż. Juliusza Mikody Programowanie urządzeń mobilnych dr inż. Andrzej Grosser na podstawie wykładu dr inż. Juliusza Mikody Wprowadzenie Android 1.0 (API level 1) - 2008 Android 1.5 Cupcake (API level 3) - 2009 Android 2.0

Bardziej szczegółowo

Programowanie Obiektowe GUI

Programowanie Obiektowe GUI Programowanie Obiektowe GUI Swing Celem ćwiczenia jest ilustracja wizualnego tworzenia graficznego interfejsu użytkownika opartego o bibliotekę Swing w środowisku NetBeans. Ponadto, ćwiczenie ma na celu

Bardziej szczegółowo

Ustawienia ogólne. Ustawienia okólne są dostępne w panelu głównym programu System Sensor, po kliknięciu ikony

Ustawienia ogólne. Ustawienia okólne są dostępne w panelu głównym programu System Sensor, po kliknięciu ikony Ustawienia ogólne Ustawienia okólne są dostępne w panelu głównym programu System Sensor, po kliknięciu ikony Panel główny programu System Sensor (tylko dla wersja V2, V3, V4) Panel główny programu System

Bardziej szczegółowo

PRZEWODNIK PO ETRADER ROZDZIAŁ XII. ALERTY SPIS TREŚCI

PRZEWODNIK PO ETRADER ROZDZIAŁ XII. ALERTY SPIS TREŚCI PRZEWODNIK PO ETRADER ROZDZIAŁ XII. ALERTY SPIS TREŚCI 1. OPIS OKNA 3 2. OTWIERANIE OKNA 3 3. ZAWARTOŚĆ OKNA 4 3.1. WIDOK AKTYWNE ALERTY 4 3.2. WIDOK HISTORIA NOWO WYGENEROWANYCH ALERTÓW 4 3.3. DEFINIOWANIE

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Programowanie obiektowe Laboratorium 1. Wstęp do programowania w języku Java. Narzędzia 1. Aby móc tworzyć programy w języku Java, potrzebny jest zestaw narzędzi Java Development Kit, który można ściągnąć

Bardziej szczegółowo

Systemy operacyjne na platformach mobilnych

Systemy operacyjne na platformach mobilnych Systemy operacyjne na platformach mobilnych Wykład 3 Grzegorz Jabłoński, Piotr Perek Katedra Mikroelektroniki i Technik Informatycznych Zagadnienia wykładu Menu opcji ListActivity własny widok własny adapter

Bardziej szczegółowo

Programowanie Urządzeń Mobilnych. Laboratorium nr 7, 8

Programowanie Urządzeń Mobilnych. Laboratorium nr 7, 8 Programowanie Urządzeń Mobilnych Laboratorium nr 7, 8 Android Temat 1 tworzenie i uruchamianie aplikacji z użyciem Android SDK Krzysztof Bruniecki 1 Wstęp Platforma Android jest opartym na Linuxie systemem

Bardziej szczegółowo

5.4. Tworzymy formularze

5.4. Tworzymy formularze 5.4. Tworzymy formularze Zastosowanie formularzy Formularz to obiekt bazy danych, który daje możliwość tworzenia i modyfikacji danych w tabeli lub kwerendzie. Jego wielką zaletą jest umiejętność zautomatyzowania

Bardziej szczegółowo

Programowanie urządzeń mobilnych. dr inż. Andrzej Grosser na podstawie wykładu dr inż. Juliusza Mikody

Programowanie urządzeń mobilnych. dr inż. Andrzej Grosser na podstawie wykładu dr inż. Juliusza Mikody Programowanie urządzeń mobilnych dr inż. Andrzej Grosser na podstawie wykładu dr inż. Juliusza Mikody Rozmieszczenie przykład Jaki układu rozmieszczający powinien zostać wykorzystany? AbsoluteLayout, TableLayout,

Bardziej szczegółowo

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak Java: otwórz okienko Programowanie w językach wysokiego poziomu mgr inż. Anna Wawszczak PLAN WYKŁADU klasy wewnętrzne, lokalne i anonimowe biblioteka AWT zestaw Swing JFrame JPanel komponenty obsługa zdarzeń

Bardziej szczegółowo

Nawigacja po długim dokumencie może być męcząca, dlatego warto poznać następujące skróty klawiszowe

Nawigacja po długim dokumencie może być męcząca, dlatego warto poznać następujące skróty klawiszowe Zestawienie wydatków rok 2015 1 Wstaw numerację stron. Aby to zrobić przejdź na zakładkę Wstawianie i w grupie Nagłówek i stopka wybierz Numer strony. Następnie określ pozycję numeru na stronie (na przykład

Bardziej szczegółowo

Zadanie Wstaw wykres i dokonaj jego edycji dla poniższych danych. 8a 3,54 8b 5,25 8c 4,21 8d 4,85

Zadanie Wstaw wykres i dokonaj jego edycji dla poniższych danych. 8a 3,54 8b 5,25 8c 4,21 8d 4,85 Zadanie Wstaw wykres i dokonaj jego edycji dla poniższych danych Klasa Średnia 8a 3,54 8b 5,25 8c 4,21 8d 4,85 Do wstawienia wykresu w edytorze tekstu nie potrzebujemy mieć wykonanej tabeli jest ona tylko

Bardziej szczegółowo

INSTRUKCJA UŻYTKOWNIKA

INSTRUKCJA UŻYTKOWNIKA INSTRUKCJA UŻYTKOWNIKA Jak przeczytać wypożyczoną książkę?... 2 Uzyskanie Adobe ID... 2 Czytanie na komputerze... 3 Uruchomienie programu... 3 Czytanie i zwracanie książek... 4 Logowanie do aplikacji...

Bardziej szczegółowo

Instrukcja użytkowania

Instrukcja użytkowania ASPEL S.A. PL 32-080 Zabierzów, os. H. Sienkiewicza 33 tel. +48 12 285 22 22, fax +48 12 285 30 30 www.aspel.com.pl Instrukcja użytkowania Konfiguracja bezprzewodowej komunikacji rejestratora AsPEKT 703

Bardziej szczegółowo

Leszek Stasiak Zastosowanie technologii LINQ w

Leszek Stasiak Zastosowanie technologii LINQ w Leszek Stasiak Zastosowanie technologii LINQ w C# 1. Wstęp - połączenie Do naszych zadań będziemy używać Microsoft Visual Studio 2010. Stwórzmy nowy projekt Windows Form Application. Mając do dyspozycji

Bardziej szczegółowo

Compas 2026 Vision Instrukcja obsługi do wersji 1.07

Compas 2026 Vision Instrukcja obsługi do wersji 1.07 Compas 2026 Vision Instrukcja obsługi do wersji 1.07 1 2 Spis treści Integracja...5 1.Compas 2026 Lan...5 Logowanie...7 Użytkownicy...8 Raporty...10 Tworzenie wizualizacji Widoki...12 1.Zarządzanie widokami...12

Bardziej szczegółowo

Arkusz kalkulacyjny EXCEL

Arkusz kalkulacyjny EXCEL ARKUSZ KALKULACYJNY EXCEL 1 Arkusz kalkulacyjny EXCEL Aby obrysować tabelę krawędziami należy: 1. Zaznaczyć komórki, które chcemy obrysować. 2. Kursor myszy ustawić na menu FORMAT i raz kliknąć lewym klawiszem

Bardziej szczegółowo

UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI

UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI UNIWERSYTET RZESZOWSKI KATEDRA INFORMATYKI LABORATORIUM TECHNOLOGIA SYSTEMÓW INFORMATYCZNYCH W BIOTECHNOLOGII Aplikacja bazodanowa: Cz. II Rzeszów, 2010 Strona 1 z 11 APLIKACJA BAZODANOWA MICROSOFT ACCESS

Bardziej szczegółowo

Laboratorium 7 Blog: dodawanie i edycja wpisów

Laboratorium 7 Blog: dodawanie i edycja wpisów Laboratorium 7 Blog: dodawanie i edycja wpisów Dodawanie nowych wpisów Tworzenie formularza Za obsługę formularzy odpowiada klasa Zend_Form. Dla każdego formularza w projekcie tworzymy klasę dziedziczącą

Bardziej szczegółowo

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost; Klasy w C++ są bardzo ważnym narzędziem w rękach programisty. Klasy są fundamentem programowania obiektowego. Z pomocą klas będziesz mógł tworzyć lepszy kod, a co najważniejsze będzie on bardzo dobrze

Bardziej szczegółowo

Podstawowe elementy GUI cz. 2 i 3 - zadania

Podstawowe elementy GUI cz. 2 i 3 - zadania Podstawowe elementy GUI cz. 2 i 3 - zadania Jak już robiliśmy wcześniej sporo rzeczy w Androidzie umieszczamy w plikach xml (np. strings.xml). Jest to dobra praktyka, w plikach zasobów możemy umieszczać

Bardziej szczegółowo

Oficyna Wydawnicza UNIMEX ebook z zabezpieczeniami DRM

Oficyna Wydawnicza UNIMEX ebook z zabezpieczeniami DRM Oficyna Wydawnicza UNIMEX ebook z zabezpieczeniami DRM Opis użytkowy aplikacji ebookreader Przegląd interfejsu użytkownika a. Okno książki. Wyświetla treść książki podzieloną na strony. Po prawej stronie

Bardziej szczegółowo

UONET+ - moduł Sekretariat. Jak wykorzystać wydruki list w formacie XLS do analizy danych uczniów?

UONET+ - moduł Sekretariat. Jak wykorzystać wydruki list w formacie XLS do analizy danych uczniów? UONET+ - moduł Sekretariat Jak wykorzystać wydruki list w formacie XLS do analizy danych uczniów? W module Sekretariat wydruki dostępne w widoku Wydruki/ Wydruki list można przygotować w formacie PDF oraz

Bardziej szczegółowo

Sposób tworzenia tabeli przestawnej pokażę na przykładzie listy krajów z podstawowymi informacjami o nich.

Sposób tworzenia tabeli przestawnej pokażę na przykładzie listy krajów z podstawowymi informacjami o nich. Tabele przestawne Tabela przestawna to narzędzie służące do tworzenia dynamicznych podsumowań list utworzonych w Excelu lub pobranych z zewnętrznych baz danych. Raporty tabeli przestawnej pozwalają na

Bardziej szczegółowo

Przewodnik Szybki start

Przewodnik Szybki start Przewodnik Szybki start Program Microsoft Publisher 2013 wygląda inaczej niż wcześniejsze wersje, dlatego przygotowaliśmy ten przewodnik, aby skrócić czas nauki jego obsługi. Pasek narzędzi Szybki dostęp

Bardziej szczegółowo

I. Program II. Opis głównych funkcji programu... 19

I. Program II. Opis głównych funkcji programu... 19 07-12-18 Spis treści I. Program... 1 1 Panel główny... 1 2 Edycja szablonu filtrów... 3 A) Zakładka Ogólne... 4 B) Zakładka Grupy filtrów... 5 C) Zakładka Kolumny... 17 D) Zakładka Sortowanie... 18 II.

Bardziej szczegółowo

Nowy szablon stron pracowników ZUT

Nowy szablon stron pracowników ZUT Nowy szablon stron pracowników ZUT Uczelniane Centrum Informatyki ZUT przygotowało nowy szablon stron pracowników, zunifikowany z obecnymi stronami ZUT. Serdecznie zachęcamy Państwa do migracji na nowy

Bardziej szczegółowo

Ćwiczenie 25 Działania matematyczne we Flashu

Ćwiczenie 25 Działania matematyczne we Flashu Działania matematyczne we Flashu ActionScript pozwala na stosowanie wszelkich działań matematycznych. Do bardziej skomplikowanych operacji wymagany jest import klasy Math. Na przykład do wygenerowania

Bardziej szczegółowo

Pokaz slajdów na stronie internetowej

Pokaz slajdów na stronie internetowej Pokaz slajdów na stronie internetowej... 1 Podpisy pod zdjęciami... 3 Publikacja pokazu slajdów w Internecie... 4 Generator strony Uczelni... 4 Funkcje dla zaawansowanych użytkowników... 5 Zmiana kolorów

Bardziej szczegółowo

www.plansoft.org plansoft.org Zmiany w Plansoft.org Panel wyszukiwania PLANOWANIE ZAJĘĆ, REZERWOWANIE SAL I ZASOBÓW

www.plansoft.org plansoft.org Zmiany w Plansoft.org Panel wyszukiwania PLANOWANIE ZAJĘĆ, REZERWOWANIE SAL I ZASOBÓW Zmiany w Plansoft.org Panel wyszukiwania... 1 Uruchamianie panelu wyszukiwania... 2 Wyszukiwanie poleceń menu... 2 Wyszukiwanie rozkładów zajęć wykładowców... 3 Wyszukiwanie rozkładów zajęć grup i użycia

Bardziej szczegółowo

Formularze w programie Word

Formularze w programie Word Formularze w programie Word Formularz to dokument o określonej strukturze, zawierający puste pola do wypełnienia, czyli pola formularza, w których wprowadza się informacje. Uzyskane informacje można następnie

Bardziej szczegółowo

Zadanie 1. Stosowanie stylów

Zadanie 1. Stosowanie stylów Zadanie 1. Stosowanie stylów Styl to zestaw elementów formatowania określających wygląd: tekstu atrybuty czcionki (tzw. styl znaku), akapitów np. wyrównanie tekstu, odstępy między wierszami, wcięcia, a

Bardziej szczegółowo

Jak zainstalować i skonfigurować komunikator MIRANDA, aby wyglądał i funkcjonował jak Gadu Gadu Tutorial by t800.

Jak zainstalować i skonfigurować komunikator MIRANDA, aby wyglądał i funkcjonował jak Gadu Gadu Tutorial by t800. Jak zainstalować i skonfigurować komunikator MIRANDA, aby wyglądał i funkcjonował jak Gadu Gadu Tutorial by t800. Wraz z niniejszym tutorialem, dołączone są 4 pliki (krok0, krok1, itd). Nie należy ich

Bardziej szczegółowo

Zawartość. Wstęp. Moduł Rozbiórki. Wstęp Instalacja Konfiguracja Uruchomienie i praca z raportem... 6

Zawartość. Wstęp. Moduł Rozbiórki. Wstęp Instalacja Konfiguracja Uruchomienie i praca z raportem... 6 Zawartość Wstęp... 1 Instalacja... 2 Konfiguracja... 2 Uruchomienie i praca z raportem... 6 Wstęp Rozwiązanie przygotowane z myślą o użytkownikach którzy potrzebują narzędzie do podziału, rozkładu, rozbiórki

Bardziej szczegółowo

Aplikacje WWW - laboratorium

Aplikacje WWW - laboratorium Aplikacje WWW - laboratorium JavaServer Faces Celem ćwiczenia jest przygotowanie aplikacji internetowej z wykorzystaniem technologii JSF. Prezentowane ćwiczenia zostały wykonane w środowisku Oracle JDeveloper

Bardziej szczegółowo

Działki Przygotowanie organizacyjne

Działki Przygotowanie organizacyjne Celem poniższego ćwiczenia jest nauczenie rozwiązywania zadań maturalnych z wykorzystaniem arkusza kalkulacyjnego. Jako przykład wykorzystano zadanie maturalne o działkach z matury w 2015 roku. Działki

Bardziej szczegółowo

Poradnik obsługi systemu zarządzania treścią (CMS) Concrete5. Moduły i bloki

Poradnik obsługi systemu zarządzania treścią (CMS) Concrete5. Moduły i bloki Poradnik obsługi systemu zarządzania treścią (CMS) Concrete5 Moduły i bloki 1 Spis treści 1. Dodawanie bloków... 3 2. Treść i Dodaj odstęp... 3 3. Galeria obrazów Amiant... 5 4. Lista stron... 8 5. Aktualności...

Bardziej szczegółowo

Tworzenie szablonów użytkownika

Tworzenie szablonów użytkownika Poradnik Inżyniera Nr 40 Aktualizacja: 12/2018 Tworzenie szablonów użytkownika Program: Plik powiązany: Stratygrafia 3D - karty otworów Demo_manual_40.gsg Głównym celem niniejszego Przewodnika Inżyniera

Bardziej szczegółowo

Instrukcja obsługi funkcji specjalnych szablonu C01 v.1.0

Instrukcja obsługi funkcji specjalnych szablonu C01 v.1.0 Instrukcja obsługi funkcji specjalnych szablonu C01 v.1.0 UWAGA 1: Przed dokonaniem jakichkolwiek zmian, zalecamy skopiować wcześniej kod html modułu do pliku na lokalnym dysku. W przypadku problemów ułatwi

Bardziej szczegółowo

Przewodnik Szybki start

Przewodnik Szybki start Przewodnik Szybki start Program Microsoft Access 2013 wygląda inaczej niż wcześniejsze wersje, dlatego przygotowaliśmy ten przewodnik, aby skrócić czas nauki jego obsługi. Zmienianie rozmiaru ekranu lub

Bardziej szczegółowo

Diagnoza Szkolna Pearsona. Instrukcja obsługi

Diagnoza Szkolna Pearsona. Instrukcja obsługi Diagnoza Szkolna Pearsona Instrukcja obsługi 1. Logowanie Aby skorzystać z systemu Diagnoza Szkolna Pearsona należy najpierw wejść na stronę diagnoza.pearson.pl i wybrać przycisk Logowanie. Następnie należy

Bardziej szczegółowo

JLR EPC. Szybki start. Spis treści. Polish Version 2.0. Przewodnik krok po kroku Przewodnik po ekranach

JLR EPC. Szybki start. Spis treści. Polish Version 2.0. Przewodnik krok po kroku Przewodnik po ekranach JLR EPC Szybki start Spis treści Przewodnik krok po kroku...2-7 Przewodnik po ekranach....8-11 Polish Version 2.0 Szybki start aplikacji JLR EPC 1. Uruchamianie aplikacji Otwórz przeglądarkę internetową

Bardziej szczegółowo

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main. Część XVI C++ Funkcje Jeśli nasz program rozrósł się już do kilkudziesięciu linijek, warto pomyśleć o jego podziale na mniejsze części. Poznajmy więc funkcje. Szybko się przekonamy, że funkcja to bardzo

Bardziej szczegółowo

APLIKACJA SHAREPOINT

APLIKACJA SHAREPOINT APLIKACJA SHAREPOINT Spis treści 1. Co to jest SharePoint?... 2 2. Tworzenie nowej witryny SharePoint (obszar roboczy)... 2 3. Gdzie znaleźć utworzone witryny SharePoint?... 3 4. Personalizacja obszaru

Bardziej szczegółowo

Zasady tworzenia podstron

Zasady tworzenia podstron Zasady tworzenia podstron Jeśli tworzysz rozbudowaną witrynę internetową z wieloma podstronami, za chwilę dowiesz się, jak dodawać nowe podstrony w kreatorze Click Web, czym kierować się przy projektowaniu

Bardziej szczegółowo

MS Excel 2007 Kurs zaawansowany Obsługa baz danych. prowadzi: Dr inż. Tomasz Bartuś. Kraków: 2008 04 25

MS Excel 2007 Kurs zaawansowany Obsługa baz danych. prowadzi: Dr inż. Tomasz Bartuś. Kraków: 2008 04 25 MS Excel 2007 Kurs zaawansowany Obsługa baz danych prowadzi: Dr inż. Tomasz Bartuś Kraków: 2008 04 25 Bazy danych Microsoft Excel 2007 udostępnia szereg funkcji i mechanizmów obsługi baz danych (zwanych

Bardziej szczegółowo

BAZA_1 Temat: Tworzenie i modyfikowanie formularzy.

BAZA_1 Temat: Tworzenie i modyfikowanie formularzy. BAZA_1 Temat: Tworzenie i modyfikowanie formularzy. Do wprowadzania danych do tabel słuŝą formularze. Dlatego zanim przystąpimy do wypełniania danymi nowo utworzonych tabel, najpierw przygotujemy odpowiednie

Bardziej szczegółowo

MS Excell 2007 Kurs podstawowy Filtrowanie raportu tabeli przestawnej

MS Excell 2007 Kurs podstawowy Filtrowanie raportu tabeli przestawnej MS Excell 2007 Kurs podstawowy Filtrowanie raportu tabeli przestawnej prowadzi: dr inż. Tomasz Bartuś Kraków: 2008 04 04 Przygotowywanie danych źródłowych Poniżej przedstawiono zalecenia umożliwiające

Bardziej szczegółowo

Komputery I (2) Panel sterowania:

Komputery I (2) Panel sterowania: Komputery I (2) Paweł Jamer Panel sterowania: Podstawowym miejscem z którego zarządzamy ustawieniami systemu Windows jest panel sterowania. Znaleźć tam możemy wszelkiego rodzaju narzędzia umożliwiające

Bardziej szczegółowo

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt.

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt. Grafika w dokumencie Wprowadzanie ozdobnych napisów WordArt Do tworzenia efektownych, ozdobnych napisów służy obiekt WordArt. Aby wstawić do dokumentu obiekt WordArt: 1. Umieść kursor w miejscu, w którym

Bardziej szczegółowo

Tworzenie prezentacji w MS PowerPoint

Tworzenie prezentacji w MS PowerPoint Tworzenie prezentacji w MS PowerPoint Program PowerPoint dostarczany jest w pakiecie Office i daje nam możliwość stworzenia prezentacji oraz uatrakcyjnienia materiału, który chcemy przedstawić. Prezentacje

Bardziej szczegółowo

UONET+ moduł Dziennik

UONET+ moduł Dziennik UONET+ moduł Dziennik Sporządzanie ocen opisowych i diagnostycznych uczniów z wykorzystaniem schematów oceniania Przewodnik System UONET+ umożliwia sporządzanie ocen opisowych uczniów w oparciu o przygotowany

Bardziej szczegółowo

Layouty. Kilka layoutów

Layouty. Kilka layoutów Layouty 1. Kilka layoutów w jednej aplikacji 2. Kilka aktywności w jednej aplikacji 3. Projektowanie layoutu: kontenery do grupowania komponentów komponenty zmiana parametrów (properties) komponentu, K-16,

Bardziej szczegółowo

Zadanie 3. Praca z tabelami

Zadanie 3. Praca z tabelami Zadanie 3. Praca z tabelami Niektóre informacje wygodnie jest przedstawiać w tabeli. Pokażemy, w jaki sposób można w dokumentach tworzyć i formatować tabele. Wszystkie funkcje związane z tabelami dostępne

Bardziej szczegółowo

Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka

Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka Makra Access 2003 wg WSiP Wyszukiwanie, selekcjonowanie i gromadzenie informacji Ewa Mirecka Makra pozwalają na zautomatyzowanie często powtarzających się czynności. Opierają się na akcjach np.: otwarcie

Bardziej szczegółowo

Microsoft Access zajęcia 3 4. Tworzenie i wykorzystanie kwerend, formularzy i raportów

Microsoft Access zajęcia 3 4. Tworzenie i wykorzystanie kwerend, formularzy i raportów Microsoft Access zajęcia 3 4 Tworzenie i wykorzystanie kwerend, formularzy i raportów Kwerendy służą do tworzenia unikalnych zestawów danych, niedostępnych bezpośrednio z tabel, dokonywania obliczeń zawartych

Bardziej szczegółowo

16) Wprowadzenie do raportowania Rave

16) Wprowadzenie do raportowania Rave 16) Wprowadzenie do raportowania Rave Tematyka rozdziału: Przegląd wszystkich komponentów Rave Tworzenie nowego raportu przy użyciu formatki w środowisku Delphi Aktywacja środowiska Report Authoring Visual

Bardziej szczegółowo

e-wsparcie Barbara Muszko Aktualizacja Twojej witryny internetowej tak prosta, jak obsługa Worda

e-wsparcie Barbara Muszko Aktualizacja Twojej witryny internetowej tak prosta, jak obsługa Worda e-wsparcie Barbara Muszko Aktualizacja Twojej witryny internetowej tak prosta, jak obsługa Worda Logowanie do panelu administracyjnego Aby móc zarządzać stroną, należy zalogować się do panelu administracyjnego.

Bardziej szczegółowo

Podstawy tworzenia prezentacji w programie Microsoft PowerPoint 2007

Podstawy tworzenia prezentacji w programie Microsoft PowerPoint 2007 Podstawy tworzenia prezentacji w programie Microsoft PowerPoint 2007 opracowanie: mgr Monika Pskit 1. Rozpoczęcie pracy z programem Microsoft PowerPoint 2007. 2. Umieszczanie tekstów i obrazów na slajdach.

Bardziej szczegółowo

Rozdział II. Praca z systemem operacyjnym

Rozdział II. Praca z systemem operacyjnym Rozdział II Praca z systemem operacyjnym 55 Rozdział III - System operacyjny i jego hierarchia 2.2. System operacyjny i jego życie Jak już wiesz, wyróżniamy wiele odmian systemów operacyjnych, które różnią

Bardziej szczegółowo

Podręcznik użytkownika programu. Ceremonia 3.1

Podręcznik użytkownika programu. Ceremonia 3.1 Podręcznik użytkownika programu Ceremonia 3.1 1 Spis treści O programie...3 Główne okno programu...4 Edytor pieśni...7 Okno ustawień programu...8 Edycja kategorii pieśni...9 Edytor schematów slajdów...10

Bardziej szczegółowo

WSTĘP DO ANDROIDA. Laboratorium

WSTĘP DO ANDROIDA. Laboratorium WSTĘP DO ANDROIDA Laboratorium I Uruchomić Android Studio I I Uruchomić Android Studio Stworzyć projekt typu Empty Activity I Uruchomić Android Studio Stworzyć projekt typu Empty Activity Zapoznać się

Bardziej szczegółowo

Email Marketing Automation:

Email Marketing Automation: Email Marketing Automation: Integracja z Google Analytics 1 Aby zintegrować system FreshMail z Google Analytics będziesz potrzebować: 1. Aktywnego konta we FreshMailu. Jeśli jeszcze nie masz swojego, możesz

Bardziej szczegółowo

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania 1) Cel ćwiczenia Celem ćwiczenia jest zapoznanie się z podstawowymi elementami obiektowymi systemu Windows wykorzystując Visual Studio 2008 takimi jak: przyciski, pola tekstowe, okna pobierania danych

Bardziej szczegółowo

Access - Aplikacja. Tworzenie bazy danych w postaci aplikacji

Access - Aplikacja. Tworzenie bazy danych w postaci aplikacji Tworzenie bazy danych w postaci aplikacji Access - Aplikacja 1. Otwórz plik zawierający bazę danych Wypożyczalni kaset video o nazwie Wypożyczalnia.mdb. 2. Utworzy kwerendę, która wyświetli tytuły i opisy

Bardziej szczegółowo

Laboratorium 9 (Więcej Aktywności, w Androidzie)

Laboratorium 9 (Więcej Aktywności, w Androidzie) Dr Mirosław Łątka Informatyka dla medycyny Jesień 2012 Laboratorium 9 (Więcej Aktywności, w Androidzie) Aplikacje systemu Android składają się z luźnego zbioru aktywności (ang. activities), z których każda

Bardziej szczegółowo