Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Wykład 1 Wprowadzenie © 2009 mgr inż. Łukasz Jopek Katedra.

Podobne prezentacje


Prezentacja na temat: "Wykład 1 Wprowadzenie © 2009 mgr inż. Łukasz Jopek Katedra."— Zapis prezentacji:

1 Wykład 1 Wprowadzenie © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

2 Układ zajęć : Wykład: Środa 1315-1400 Sala E2 ( WEIE )
15 godzin wykładu zorganizowane w postaci 15 jednogodzinnych wykładów Zaliczenie/egzamin w formie pisemnej Środa Sala E2 ( WEIE ) © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

3 Układ zajęć : Laboratorium: Środa 11:15 - 13:00 Sala 110 ( WEIE )
15 godzin laboratoriów zoogranizowanych po dwie godziny ,co dwa tygodnie Zaliczenie w postaci projektu Środa 11: :00 Sala 110 ( WEIE ) © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

4 Wykład – wykaz zagadnień:
Podstawy budowy i programowania urządzeń mobilnych (telefon komórkowy, PDA - Personal Digital Assistant) Wprowadzenie do Javy MicroEdition (J2ME) Grafika 2D i 3D w J2ME (API niskiego poziomu) GUI w J2ME Połączenia sieciowe w J2ME Składowanie danych w urządzeniach mobilnych przy wykorzystaniu J2ME Dystrybucja programów w J2ME Programowanie i testowanie w Microsoft Mobile ASP.NET Programowanie i testowanie w Symbian OS Programowanie i testowanie w Adroid OS Podstawy i rola Objective C w rozwiązaniach mobilnych Laboratorium: Tworzenie oprogramowanie na telefony komórkowe w środowisku J2ME © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

5 Literatura: Literatura podstawowa:
1 J2ME. Java dla urządzeń mobilnych. Ćwiczenia Krzysztof Rychlicki-Kicior ISBN: X Helion 2006 2 Krzysztof Rychlicki Kicior "J2ME. Praktyczne projekty" Helion ISBN: 3 Marek Wierzbicki "Java. Programowanie obiektowe" Helion 2006 ISBN: 4 Kim Topley "J2ME. Almanach" O'Reilly ISBN: Literatura uzupełniająca: 1.Miller B.M., Bisdikian Ch.: Bluetooth, Helion, Gliwice, 2003. 2.White, James i Hemphill, Davies (2002) "Java 2 Micro Edition. Java in Small Things.", Manning Publications Co., Greenwich, 2002 3. Internet © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

6 Podstawy budowy i programowania urządzeń mobilnych
(telefon komórkowy, PDA - Personal Digital Assistant) © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

7 CDC(Connected Device Configuration)
Podstawy budowy i programowania urządzeń mobilnych (telefon komórkowy, PDA - Personal Digital Assistant) CDC(Connected Device Configuration) Konfiguracja CDC (ang. Connected Device Configuration) jest konfiguracją środowiska Java ME zdefiniowanych przez Java Community Process. Konfiguracja CDC przeznaczona jest dla urządzeń wyposażonych w ok kB pamięci i pracujących z 32-bitowymi procesorami, czyli np. dla wideotelefonów konsol gier, zestawów audio-wideo, PDA. Specyfikacja znajduje się w dokumentacji JSR-36 i JSR-218. Jest ona przeznaczona dla urządzeń posiadających: stałe połączenie z siecią, 32 bitowy procesor, minimum 512KB dostępnej pamięci ROM, minimum 256KB pamięci operacyjnej RAM, graficzny interfejs użytkownika. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

8 W stosunku do CDC , CLDC brakuje między innymi:
Konfiguracja CLDC (ang. Connected Limited Device Configuration) jest bardziej ograniczoną wersją CDC i jest zdefiniowany przez Java Community Process. Konfiguracja CLDC jest przeznaczona dla urządzeń wyposażonych w około 512 kB pamięci i pracujących z 16- lub 32-bitowymi procesorami, czyli np. dla telefonów komórkowych, notesów elektronicznych czy pagerów. W stosunku do CDC , CLDC brakuje między innymi: obsługę działań na liczbach zmiennoprzecinkowych, uruchamianie kodu natywnego dzięki JNI (ang. Java Native Interface), obsługę słabych referencji, serializację obiektów, definiowanie przez użytkownika loaderów klas, obsługę mechanizmu debugowania. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

9 J2ME - Mobile Information Device Profile (MIDP)
MIDP jest uzupełnienie konfiguracji CLDC o odpowiednie klasy języka Java przeznaczone dla urządzeń mobilnych jak np. telefony komórkowe. Specyfikacja MIDP jest rozwijana przez Java Community Process (JCP). W 2000 r. udostępniono wersję 1.0. W 2002 roku wersję 2.0 MIDP. Programy napisane z wykorzystaniem MIDP noszą nazwę MIDletów (szerzej o MIDletach będzie mowa w dalszej części wykładu oraz na laboratorium). Uruchamiane są w środowisku K virtual machine. Profil MIDP zawiera bardziej rozbudowaną obsługę platformy Java niż sama konfiguracja CLDC . MIDP wymagają zatem więcej pamięci. Specyfikacja CLDC wymaga przynajmniej 120 kB pamięci RAM (Random Accesss Memory) na przechowywanie specyfikacji MIDP, oraz co najmniej 32 kB na stos. Oprócz tego wymaga minimum 8 kB pamięci nieulotnej,jest ona potrzebna, aby MIDlety mogły zapisywać dane – np.. Adresy i nr telefony w przypadku MIDletu pracującego jako książka adresowa. Urządzenia korzystające z MIDP powinny być wyposażone w ekrany umożliwiające wyświetlenie co najmniej dwóch kolorów w rozdzielczości minimum 96 na 54 pikseli. Oprócz tego , do komunikacji z użytkownikiem posiadać powinny jedno lub więcej następujących mechanizmów: klawiatura telefonu, klawiatura QWERTY, ekran dotykowy. Ich wyposażenie musi także zapewniać obsługę protokołu HTTP 1.1. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

10 Wymagania programowe Minimalne założenia:
Minimalne jądro do zarządzania sprzętem (np. obsługa przerwań, wyjątków, minimalne szeregowanie). Jądro musi zapewnić co najmniej jeden szeregowalny wątek, by uruchomić Virtualną Maszynę Javy. Mechanizm czytania i pisania z nieulotnej pamięci aby utrzymać API dostęp do czytania i pisania w bezprzewodowej sieci urzadzenia aby utrzymać API mechanizm zapewniający zapisywanie znaczników czasowych w rekordach zapisanych w zasobach pamięci trwałej minimalna zdolność do zapisywania w mapie bitowej graficznego wyświetlacza mechanizm przechwytujący dane z wejścia z jednego (lub więcej) z trzech urządzeń machanizm zarządzający cyklem życia aplikacji urządzenia © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

11 Architektura MIDP © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

12 Najniższy blok (MID) przedstawia poziom sprzętu urządzenia przenośnego
Najniższy blok (MID) przedstawia poziom sprzętu urządzenia przenośnego. Jego część stanowi native system software, który zawiera system operacyjny i biblioteki użyte przez konkretne urządzenie. Powyżej jest warstwa oprogramowania, czyli CLDC. Tutaj także znajduje się K-Virtual Machine (KVM) oraz skojarzone biblioteki zdefiniowane przez specyfikację CLDC. CLDC posiada dwa rodzaje API: 1. MIDP: Zbiór API zdefiniowanych przez MIDP. 2. OEM-specific: Klasy, które mają dostęp do specyficznych funkcjonalności konkretnego urządzenia. Nie zapewniają zatem przenośności aplikacji, które z nich korzystają. Spowodowane jest to dużą różnorodnością urządzeń mobilnych, dostępnych na rynku. Na samym szczycie znajdują się MIDP: Aplikacja MIDP lub MIDlet, używa tylko API zdefiniowane przez specyfikację MIDP i CLDC. Używana najczęściej, zapewnia przenośność aplikacji. OEM-Specific: Aplikacje wykorzystujące specyficzne możliwości danych urządzeń. Aplikacje nie są przenośne. Native: rodzima aplikacja, która nie jest napisana w Javie. Pakiety i klasy Pakiety i klasy wchodzące w skład J2ME - MIDP: java.util.Timer - ułatwienie dla wątków w szeregowaniu zadań java.util.TimerTask - zadanie które może być szeregowane przez Timer javax.microedition.rms - mechanizm obsługi zasobu pamięci trwałej javax.microedition.midlet - definicja aplikacji MIDP, interkacji między nimi oraz środowiska w którym aplikacja działa javax.microedition.io - obsługa sieci oparta na CLDC javax.microedition.lcdui - interfejs użytkownika dla aplikacji © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

13 Zmiany w MIDP 2.0, w stosunku do MIDP 1.0
Rozszerzony interfejs użytkownika Modyfikacja elementów takich jak : Popup ChoiceGroup czy Alert ekranu . Media Support Media Support Dodana obsługa dźwięku w formacie .wav, oraz możliwość wykorzystania mediów strumieniowych Game Support Game API to rozszerzenie zapewniające nowe możliwości twórcom gier w zakresie wykorzystania grafiki np. poprzez długo oczekiwane sprite'y i warstwy. Expanded Connectivity(Rozszerzona Łączność) Wsparcie dla standardów HTTP, HTTPS, datagramów, gniazd oraz komunikacji wykorzystującej port szeregowy. Oprócz tego oferuje wsparcie szyfrowania transmisji za pomocą protokołów SSL, WTLS czy podpisywania midletów certyfikatami X.509. Push Architecture Model push, umożliwia przesyłanie danych z serwera do aplikacji, np aktywacje zainstalowanych na urządzeniu midletów, przesyłanie komunikatów i powiadomień wprost do aplikacji. Over-the-air (OTA) Provisioning Ttechnika instalowania, uruchamiania i aktualizacji midletów over-the-air (OTA), stała się oficjalnie częścią specyfikacji. End-to-end Security Wsparcie dla technologii takich jak : HTTPS i wykorzystuje istniejące standardy, takie jak SSL, WTLS, czy podpisu elektronicznego. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

14 J2ME – MIDlet, budowa i przykład
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

15 Szkielet MIDletu import javax.microedition.midlet.MIDlet;
public class PierwszyMIDlet extends MIDlet { public void startApp(){ } public void pauseApp(){ public void destroyApp(boolean){ /** Opcjonalny konstruktor:**/ © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

16 MIDlet musi mieć również publiczny bezargumentowy konstruktor :
public NazwaKlasy() {} W przypadku zwykłej aplikacji, napisanej w języku JAVA, metoda wywoływania inicjalizacji obiektów była statyczną metodą main(), w przypadku MIDletu jest to public void startApp() {} MIDlet może ulec zawieszeniu, w tym celu wywołać można metodę public void pauseApp() {} W tym momnecie MIDlet zwalnia swoje zasoby, zawieszone jest działanie "timerów". Ekran wówczas może być przekazany np. innemu MIDletowi. W stan zawieszenia może również dobrowolnie wprowadzić siebie aplikacja. Dokonuje tego wywołując metodę Public notifyPaused() {} W przypadku wywołania metody notifyPaused() platforma nie wywołuje już metody pauseApp(). Zakłada, że MIDlet wywołując metodę notifyPaused() jest już gotowy do przejścia w stan zawieszenia. Dlatego metoda pauseApp() często poprzedza wywołanie metody notifyPaused(). © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

17 Aby powrócić ze stanu zawieszenia w stan aktywny, MIDlet wywołuje bezargumentową metodę
resumeRequest() {} Informuje ona informuje maszynę wirtualną, że MIDlet jest gotowy do działania. Uruchomiony zostanie, gdy tylko przydzielone mu będą odpowiednie zasoby, co nastąpi, gdy takie będą (np.. Zwolni je inny MIDlet). W przypadku powrotu ze stanu zawieszenia w stan aktywny, ponownie wywoływana jest metoda Public startApp() {} Oczywiście rodzi to niebezpieczeństwo podwójnego alokowania pamięci podczas inicjacji obiektów w tej metodzie. Trzeba więc albo inicjować obiekty w konstruktorze lub wprowadzić inne metody zabezpieczeń przed dublowaniem się obiektów. Zakończyć działanie MIDletu można za pomocą metody : public void destroyApp(boolean) {} Tutaj usuwanie są obiekty, ewentualne dane zapisywane są w pamięci trwałej. MIDlet można również zakończyć wywołując metodę notifyDestroyed() Platforma nie wywołuje wówczas metody destroyApp(). Przyjmuje, iż aplikacja została już przygotowana do zamknięcia. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

18 Grafika 2D i 3D w J2ME (API niskiego poziomu)
Źródło : O'reilly - j2me in a nutshell, str. 397 © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

19 definiowania ich koloru, czy wyświetlanie tekstu
Klasa Canvas jest klasą dziedziczącą po klasie Displayable. Udostępnia ona powierzchnię ekranu do dowolnych operacji graficznych. Nie można dodać do niej komponentów, pozwala jedynie na niskopoziomowe operacje graficzne. Klasa Canvas nie udostępnia żadnych możliwości graficznych. Jest to zadanie klasy Graphics. Natomiast klasa Canvas przenosi obraz z obiektu klasy Graphics na ekran. Zatem klasa Canvas pozwala na dostęp do pojedynczych pikseli wyświetlanych na ekranie urządzenia. Zawiera metody pozwalające np. na rysowanie figur geometrycznych, definiowania ich koloru, czy wyświetlanie tekstu (z uwzględnieniem wielkości, czcionki, czy pozycji na ekranie.) Nie definiuje natomiast elementów interfejsu użytkownika, takich jak przycisku czy pola tekstowe. Te elementy udostępniają inne klasy, i są to elementu należące do API wysokiego poziomu. Klasy Canvas oraz Graphics zawarte są w pakiecie javax.microedition.lcdui, zatem wymagane jest użycie Dodatkowej paczki: import javax.microedition.lcdui.*; © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

20 public int getHeight() public int getWidth()
Klasa Canvas zawiera metody, dzięki którym możemy sprawdzić cechy urządzenia (ekranu). Poniższe metody pozwalają pozyskać wymiary ekranu (w pikselach) i sprawdzić, czy urządzenie dostarcza podwójne buforowanie: public int getHeight() public int getWidth() public boolean isDoubleBuffered() Podwójne buforowanie polega na tym, iż zmiany w wyglądzie nie są widoczne od razu dla użytkownika, a przygotowywane są w buforze poza ekranem, a następnie wyświetlanie na nim. Pomaga to uniknąć migotania ekranu. Z kolei informację o liczbie wyświetlanych przez urządzenie kolorów możemy poznać dzięki metodom z klasy Display: public boolean isColor() public int numColors() © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

21 protected abstract void paint(Graphics g)
Klasa Canvas wywiedziona z Displayable. A już Displayable daje możliwość dołączenia do niej komend. Można zatem dołączać je do obiektów klas rozszerzających klasę Canvas. Metoda korzystania z klasy Canvas : będziemy definiowanie klasy wywodzące się z niej, wypełniając jedyną abstrakcyjną w niej metodę: protected abstract void paint(Graphics g) Korzystając z podanego nam jako argument (przez maszynę wirtualną) argumentu typu Graphics, będziemy w tej metodzie definiować wygląd naszego obiektu. Oprócz tego Canvas posiada także wiele zdefiniowanych metod, pozwalających na np. Ponowne narysowanie obiektu (metoda repaint()), reagować na naciśnięcie lub zwolnienie przycisku klawiatury, czy zdarzenie wygenerowane przez inne urządzenie wejściowe (np. Dotkniecie ekranu dotykowego czy przesunięcie rysika). Do tego dochdzą metody pozwalające sprawdzić właściwości ekranu. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

22 Przykład użycia dla Canvas
private class Ekran extends Canvas{ String tekst =” ”; int szerokosc,wysokosc; public Ekran(String napis){ tekst = napis; szerokosc = getWidth(); wysokosc = getHeight(); } public paint(Graphics g){ g.setColor(0xffffff); //zmiana aktualnego koloru // Rysowanie prostokąta o rozmiarze ekranu g.fillRect(0, 0, ScreenWidth, ScreenHeight); g.setColor(255,0,0); //zmiana aktualnego koloru // Wyświetlenie tekstu na środku ekranu g.drawString(label, ScreenWidth/2, ScreenHeight/2, g.HCENTER|g.TOP); repaint(); //Narysowanie ekranu od nowa. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

23 Przykład użycia dla Canvas c.d.
import javax.microedition.midlet.MIDlet; import javax.microedition.lcdui.*; public class PierwszyMIDlet extends MIDlet { private Display display; private class Ekran extends Canvas{ String tekst =” ”; int szerokosc,wysokosc; public Ekran(String napis){ tekst = napis; szerokosc = getWidth(); wysokosc = getHeight(); } public paint(Graphics g){ g.setColor(0xffffff); //zmiana aktualnego koloru // Rysowanie prostokąta o rozmiarze ekranu g.fillRect(0, 0, ScreenWidth, ScreenHeight); g.setColor(255,0,0); //zmiana aktualnego koloru // Wyświetlenie tekstu na środku ekranu g.drawString(label, ScreenWidth/2, ScreenHeight/2, g.HCENTER|g.TOP); public void startApp(){ display = Display.getDisplay(this); display.setCurrent(new Ekran(„Pierwszy MIDlet")); public void pauseApp(){ public void destroyApp(boolean unconditional){ © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

24 Przykład klasy pozwalającej na wyświetlanie obrazów
na ekranie urządzenia import javax.microedition.midlet.*; import javax.microedition.lcdui.*; class ImageInCanvas extends Canvas { Image image; public ImageDemoCanvas () { try { image = Image.createImage (/logo.png); } catch (IOException e) { throw new RuntimeException („Unable to load Image ”+e); public void paint (Graphics g) { g.setGrayScale (255); g.fillRect (0, 0, getWidth (), getHeight ()); g.drawImage (image, 0, 0, Graphics.TOP | Graphics.LEFT); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

25 Ciekawsze metody klasy Graphics
public void drawRect(int x, int y, int width, int height); // native public void drawRoundRect(int x, int y, int width, // native int height, int arcWidth, int arcHeight); public void drawString(String str, int x, int y, // native int anchor); public void drawSubstring(String str, int offset, int len, // native int x, int y, int anchor); public void fillArc(int x, int y, int width, int height, // native int startAngle, int arcAngle); public void fillRect(int x, int y, int width, int height); // native public void fillRoundRect(int x, int y, int width, // native public void setClip( int x, int y, int width, int height); public void translate( int x, int y); public int getColor(); public void setColor( int RGB); public void setColor( int red, int green, int blue); public Font getFont(); public void setFont( Font font); public int getTranslateX(); public int getTranslateY(); public void clipRect(int x, int y, int width, int height); public void drawArc(int x, int y, int width, int height, // native int startAngle, int arcAngle); public void drawChar(char character, int x, int y, // native int anchor); public void drawChars(char[] data, int offset, // native int length, int x, int y, int anchor); public void drawImage(Image img, int x, int y, // native public void drawLine( int x1, int y1, int x2, int y2); // native © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

26 W przypadku klawiatury mamy do dyspozycji następujące metody :
Oprócz operacji związanych z ekranem urządzenia, klasa Canvas zawiera także metody obsługi zdarzeń z urządzeń wejściowych, takich jak klawiatura, czy ekran dotykowy, czy np. Rysik (w przypadku urządzeń typu PDA). W przypadku klawiatury mamy do dyspozycji następujące metody : protected void keyPressed(int keyCode) -Klawisz naciśniety protected void keyReleased(int keyCode) -Klawisz puszczony protected void keyRepeated(int keyCode) -Klawisz przytrzymamy Niektóre klawisze zdefiniowane są na stałe: KEY_NUMn - gdzie n, to oznaczenie kolejnych przycisków (od 0 do 9), KEY_STAR - klawisz oznaczający klawisz ze znaczkiem gwiazdki, KEY_POUND - klawisz ze znaczkiem hash. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

27 Przykład użycia dla Canvas (obsługa zdarzeń)
private class Ekran extends Canvas { public konstruktor() { String s = ""; } // Pozostałe instrukcje // public void paint(Graphics g){ g.setColor(0,255,0); g.fillRect(ScreenWidth/2, ScreenHeight/2, ScreenWidth, ScreenHeight); g.setColor(0,0,0); g.drawString(s, ScreenWidth/2, ScreenHeight/2, g.HCENTER|g.TOP); public void Klawisz(){ public void keyPressed (int key) { s = "Naciśnięty klawisz: "+key; repaint(); repaint(); public void keyReleased (int key) { s = "Puszczony klawisz: "+key; repaint(); public void keyRepeated (int key) { s = "Przytrzymany klawisz: "+key; repaint(); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

28 GUI w J2ME © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

29 GUI J2ME (API wysokiego poziomu)
Źródło : O'reilly - j2me in a nutshell, str. 397 © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

30 Komponenty wysoko-poziomowego GUI:
Alert – Służy do wyświetlania wiadomości o nagłym zdarzeniu. Może zawierać zarówno tekst jak i grafikę. Alert testAlert = new Alert(„Belkla gorna", „Tresc alertu.", null, AlertType.INFO); testAlert.setTimeout(Alert.FOREVER); Typ alertu Opis ALARM Informowanie użytkownika o nagłych zdarzeniach CONFIRMATION Prośba do użytkownika o potwierdzenia akcji ERROR Informacja o błędzie INFO Informacja dla użytkownika WARNING Ostrzeżenie o niebezpiecznych operacjach © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

31 Komponenty wysoko-poziomowego GUI:
ChoiceGroup – element dający możliwość wyboru z listy opcji. Może zawierać tekst jak i grafikę. Obrazek jest połozy obok tekstu i traktowany jako jeden obiekt. private ChoiceGroup cg_kierunek, cg_przystanek, cg_typ cg_typ = new ChoiceGroup("Typ srodka komunikacji : ", Choice.EXCLUSIVE); cg_typ.append("Tramwaj", null); cg_typ.append("Autobus", null); TextBox – kontrolka umożliwiająca użytkownikowi na wpisanie i edycje tekstu. Ma ustaloną maksymalną ilość tekstu. Maksymalny rozmiar tekstu może być większy od ekranu, na którym ma zostać wyświetlony, wtedy automatycznie pojawiają się paski przewijania. private TextBox tekst; tekst = new TextBox(„Belka górna",„Tekst domyślny",20,0); Trzeci parametr oznacza maksymalny rozmiar tekstu, czwarty parametr pozwala na włączenie ograniczeń co Do edycji tekstu. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

32 Komponenty wysoko-poziomowego GUI:
TekstField – podobnie jak TextBox słuzy do wprowadzania tekstu, z ta różnica, ze pozwana na Wprowadzenie masek ,np. w przypadku wpisywania nr telefonu klawiatura automatycznie przełączy Na tryb wprowadzania liczb. private TextField tekst; tekst = new TextField(„Belka górna",„Tekst domyślny",20,0); Trzeci parametr oznacza maksymalny rozmiar tekstu, czwarty parametr pozwala na włączenie ograniczeń co Do edycji tekstu. Ticker – pasek znajdujący się na górze ekranu, w którym przejawia się przewijający się tekst. Parametry takie jak szybkość czy kierunek przesuwania się tekstu są zdefiniowanie przez urządzenie I nie ma możliwości ich zmiany. Ticker aTicker = new Ticker („Ticker J2ME!"); Forma.setTicker(aTicker); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

33 Służyć jako regulator poziomu jakiejś wartości.
Gauge – Element odpowiadający za działanie wszelkiego rodzaje paski postępu, może tez Służyć jako regulator poziomu jakiejś wartości. private Gauge glosnosc; glosnosc = new Gauge(„Glosnosc",true,10,1); Pierwszy parametr określa etykietę regulatora Drugi parametr określa, czy można zmieniać jego ustawienia Trzeci parametr określa wartość maksymalną Czwarty parametr oznacza wartość, jaka suwak przymnie po zainicjowaniu. Na ekranie wyświetlany na raz może być tylko jeden obiekt z wyżej wymienionych, ponieważ na raz wyświetlany może być tylko jeden obiekt dziedziczący po klasie „Screen”. A co jeśli chcemy Wyświetlić na raz kilka obiektów, np. TextBox z podpisem ? Private TexBox teskt; / reszta instrukcji / Public startApp(){ display = Display.getDisplay(this); tekst = new TextBox("Belka górna","Tekst domyślny",20,0); display.setCurrent(tekst); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

34 Znajdujących się wewnątrz.
W przypadku, gdy chcemy wyświetlić na ekranie na raz kilka elementów, trzeba je umieścić w jakimś kontenerze. W tym celu można zastosować element „Form”. „Form” zajmuje się wyświetlaniem i pozycjonowaniem elelmentów Znajdujących się wewnątrz. public void startApp(){   display = Display.getDisplay(this); txt = new TextField("Belka górna","Tekst domyślny",20,0); cg_typ = new ChoiceGroup("Typ srodka komunikacji : ", Choice.EXCLUSIVE); forma1 = new Form("Demo Form"); cg_typ.append("Tramwaj", null); cg_typ.append("Autobus", null); forma1.append(cg_typ); forma1.append(txt); display.setCurrent(forma1); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

35 Oprócz „Form” istnieje jeszcze inny komponent, pozwalający na grupowanie wewnątrz innych elementów
graficznych. Jest to komponent „List”, który działa nieco podobnie do elementu „choice”. Użytkownik może przeglądać elementy tej listy, a dopiero wybranie któregoś elementu powoduje jakaś akcje Dla aplikacji. Dokonuje się tego za pomocą komponentu „Command”. CommandListener Jeśli klasa implementuje interfejs CommandListener to można tworzyc w niej interaktywne przyciski typu Button. Jest to dość popularne rozwiązanie do obsługi komend. W J2ME niestety nie mamy żadnych buttonów itp. więc interakcja odbywa się poprzez klawisze na telefonie. Aby ją obsłużyć należy dodać obiekt typu Command do obiektu tworzącego formę w aplikacji. Konstruktor obiektu Command wygląda następująco: publi Command(String tekst, int typ, int priorytet) tekst - nazwa wyświetlana typ - typ komendy (Ok, Exit, Cancel, Help) priorytet - służy do układania kolejności. Można też wg niego rozróżniać komendy © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

36 © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ
public class PierwszyMIDlet extends MIDlet implements CommandListener { private Display display; private TextBox tekst; private TextField txt; public Form forma1; private ChoiceGroup cg_typ; public void startApp(){   display = Display.getDisplay(this); txt = new TextField("Belka górna","Tekst domyślny",20,0); cg_typ = new ChoiceGroup("Typ srodka komunikacji : ", Choice.EXCLUSIVE); forma1 = new Form("Demo Form"); cg_typ.append("Tramwaj", null); cg_typ.append("Autobus", null); forma1.append(cg_typ); forma1.append(txt); forma1.addCommand(new Command("Exit",Command.EXIT,0)); forma1.setCommandListener(this); display.setCurrent(forma1); } public void commandAction(Command c, Displayable d) { if (c.getCommandType()==Command.EXIT) notifyDestroyed(); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

37 © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ
public class PierwszyMIDlet extends MIDlet implements CommandListener { private Display display; private TextField a,b,Wynik; public Form forma1; private Command exitCommand; private Command calculateCommand; private ChoiceGroup dzial_typ; public void startApp(){   display = Display.getDisplay(this); a = new TextField(„Liczba 1: ",„0",20,0); b = new TextField(„Liczba 2: ",„0",20,0); Wynik = new TextField(„Wynik: ",„0",20,0); dzial_typ = new ChoiceGroup(„Wybierz dzialanie : ", Choice.EXCLUSIVE); forma1 = new Form("Demo Form"); dzial_typ.append(„dodaj", null); dzial_typ.append(„odejmnij", null); forma1.append(dzial_typ); forma1.append(a); forma1.append(b); forma1.append(Wynik); exitCommand = new Command("Wyjście", Command.SCREEN, 2); calculateCommand = new Command("Oblicz", Command.SCREEN, 1); forma1.addCommand(exitCommand ); forma1.addCommand(calculateCommand); forma1.setCommandListener(this); display.setCurrent(forma1); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

38 © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ
public void commandAction(Command c, Displayable s) { if (c == exitCommand) { destroyApp(false); notifyDestroyed(); } if (c == calculateCommand) { float A,B,wynik; try { A = Float.parseFloat(a.getString().equals("")?"0":a.getString()); B = Float.parseFloat(b.getString().equals("")?"0":b.getString()); catch (Exception e) { A=B=0; wynik = A + B; wynik.setString(„”+wynik); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

39 Połączenia sieciowe w J2ME
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

40 Źródło: http://developers. sun
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

41 Źródło : O'reilly - j2me in a nutshell, str. 326
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

42 Urządzenia mobilne prawie zawsze posiadają na możliwość komunikacji z innym urządzeniami tego typu oraz często także z Internetem. W przypadku J2ME problem ten rozwiązano tworząc Interfejs Connection, który reprezentuje dowolne połączenie (np. za pomocą protokołu http czy też innego). Z interfejsu tego wywodzą się interfejsy realizujące różne rodzaje połączenia. Jest on klasą bazową dla wielu metod przesyłania danych zarówno w sieci jak i w obrębie urządzenia. Interfejs Connection ma tylko jedną metodę: public abstract void close() throws IOException interfejs reprezentujący dowolne połączenie nie ma metody otwierającej takie połączenie. Zestawienie połączenia jest możliwe za pomocą odpowiednich metod klasy Connector. Klasa Connector zawiera tylko statyczne metody i są to metody pozwalające utworzenie referencji  do interfejsu Connection i realizacji połączenia danego typu.  Metody te wyglądają następująco : public static Connection open(String nazwa) throws IOException public static Connection open(String nazwa,int tryb_dostepu ) throws IOException public static Connection open(String nazwa,int tryb_dostepu,boolean czas) throws IOException © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

43 {protokół}:[{adres_sieciowy}][{parametry}]
Metody przedstawione powyżej zwracają referencję do interfejsu Connection oraz pozwalają na nawiązanie połączenia z innym urządzeniem. Urządzenie jest określane w pierwszym argumencie.  Połączenie może zachodzić w trybie czytania, pisania, lub obydwu jednocześnie, przy czym tryb połączenia w obie strony jest przyjmowany domyślnie. Oprócz tego czas oczekiwania na połączenie może być ograniczany. Każda z metod open zwraca referencję do obiektu utworzonego na podstawie klasy implementującej Connection. Mogą to być referencje klasu HttpConnection (dla protokołu http), StreamConnection (dla gniazd),  DatagramConnection (dla datagramów). Postać nazwy urządzenia, z którym chcemy nawiązać polaczenie wygląda następująco : {protokół}:[{adres_sieciowy}][{parametry}] Poniżej przekłady nazw dla różnych urządzeń : socket://www.kojot.test.com:8080 datagram://:555 file:///home/user/plik © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

44 Protokół HTTP Protokół ten wykorzystywany jest do przesyłania danych pomiędzy serwerem WWW, a klientem, a w tym celu korzysta z gniazd. Jest też jest jedynym protokołem, o którym się zakłada, że jest obsługiwany przez każde urządzenie spełniające założenia MIDP. Jednakże w przypadku małych urządzeń takich jak telefon komórkowy istnieje problem braku wbudowanej przeglądarki WWW. Wprawdzie producent ma obowiązek implementacji protokołu http, ale czasem jest to rodzaj bramy ,która tłumaczy komunikaty http na postać rozumianą przez urządzenie. Poniżej przykład obrazujący sposób nawiązania połączenia z danym adresem internetowym : hc = (HttpConnection)Connector.open("http://www.wp.pl Connector.READ_WRITE"); Jak widać podaliśmy dwa parametry metodzie open : nazwę urządzenia (http), adres (www.wp.pl), oraz tryb dostępu. Nie narzuciliśmy ograniczenia czasu dostępu (np. zakładamy, że dysponujemy dobrym łączem). Podstawowe czynności które należy wykonać, aby skorzystać z HttpConection do pobrania strony www : Tworzymy łańcuch zawierający adres URL strony WWW którą chcemy pobrać, następnie wywołać metodę open() i utworzyć obiekt klasy HttpConnection.  Czasem trzeba ustalić rodzaj żądania oraz parametry . Domyślnym żądaniem jest GET. Następnie należy sprawdzić za pomocą metody getResponseCode() czy serwer odpowiedział pozytywnie na żądanie. Podobnie jak w przypadku magazynów musimy posłużyć się strumieniami, zatem wywołujemy metodę openInputStream() lub openDataInputStream() i w ten sposób uzyskujemy dostęp do strumienia wejściowego. Na koniec zamykamy strumień wejściowy. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

45 Przykład wykorzystania klasy HTTPConnection:
import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; public void startApp() throws IOException{ HttpConnection hc = null; InputStream is = null; int ch; try{ hc = (HttpConnection)Connector.open("http://www.wp.pl Connector.READ_WRITE"); is = hc.openInputStream(); while ((ch = is.read()) != -1) { str.append((char)ch); } finally { if (is != null) is.close(); if (hc != null) hc.close(); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

46 stałe klasy HttpConnection
Zatem obiekt typu HttpConection może być wykorzystywany do przesyłania danych w postaci strumieni danych wejściowych i wyjściowych, dodatkowo można określić ich długość, typ i sposób kodowania. Metody te pochodzą z klasy ContentConnection. Serwer www wysyła odpowiedź, którą można odebrać za pomocą metody getResponseCode(), poniżej przykłady odpowiedzi : stałe klasy HttpConnection Znaczenie HTTP_OK Zasób dostępny bez błędu (200) HTTP_MOVED_PERM Zasób przeniesiony pod inny adres i jest podany w nagłówku (301) HTTP_SEE_OTHER Należy wysłać żądanie GET pod adres podany w nagłówku (303) HTTP_BAD_REQUEST Żądanie dotarło w postaci zniekształconej i nie może być zrealizowane (400) HTTP_FORBIDDEN Żądanie nie może być zrealizowane (403) HTTP_NOT_FOUND Zasób nie istnieje (404) © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

47 nazwa1=wartość&nazwa2=wartość&nazwa3=wartość
Zapytania i odpowiedzi w protokole http Komunikat przesyłający żądanie do serwera www składa się z trzech elementów Wiersz zawierający żądanie HTTP, po nim nowa linia, Nagłówki żądania, każdy w nowym wierszu, po nich linia wolna – jest to element opcjonalny, Dane dodatkowe potrzebne do wykonania żądania - występuje gdy jest niezbędny. Przykłady żądań : Żądanie Znaczenie Wartość GET HttpConnection.GET Prośba o przesłanie pliku o podanej ścieżce HEAD HttpConnection.HEAD Jak wyżej, z tą różnica, że wysyłane są jedynie nagłówki, bez danych POST HttpConnection.POST Metoda stosowana, gdy na stronie są formularze. Postać parametrów żądań umieszczanych w adresie lub w ciele żądania wygląda następująco: nazwa1=wartość&nazwa2=wartość&nazwa3=wartość © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

48 OutputStream os = sc.openOutputStream();
Gniazda ( Socket ) Gniazda w J2ME nie różnią się zbytnio od gniazd z innych wersji JAVY , czy też innych języków (np. C/C++). Jedyna różnicą jest to, że standard MIDP nie wymaga obsługi gniazd. Powodowane jest to tym, że gniazda wykorzystują protokół TCP/IP, a urządzenia mobilne nie koniecznie muszą mieć dostęp do Internetu i w ogóle obsługiwać stosu TCP/IP. Klasa StreamConnection dziedziczy z Connection. Zatem chcą uzyskać połączenie za pomocą gniazda, z serwerem świadczącym usługi na jakimś porcie musimy utworzyć połączenie za pomocą metody open(). Otwarcie połączenia może mieć jedną z poniższych postaci : StreamConenection sc = (StreamConnection)Connector.open("socket://:32839"); StreamConenection sc = (StreamConnection)Connector.open("socket:// :80") StreamConenection sc = (StreamConnection)Connector.open("socket://jakis_adres:80") ; Sposób nawiązywania połączenia jest nadal taki sam. Jak widać podaliśmy dwa parametry metodzie open : nazwę urządzenia (socket), i adres (www.wp.pl). Jeżeli połączenie może być nawiązane, to należy otworzyć strumień wyjściowy i  za pośrednictwem tego strumienia wysłać polecenie do nasłuchującego serwera.  Otwarcie  strumienia wyjściowego może mieć poniższą postać: OutputStream os = sc.openOutputStream(); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

49 OutputStream os = sc.openInputStream() ;
Za pomocą tego strumienia należy wysłać zrozumiałe dla serwera zapytanie. Jeżeli będzie to serwer www to zapytanie może mieć postać: "GET / HTTP/1.1\n\n" Zapytanie należy przesłać jako ciąg bajtów. Należy pamiętać, że urządzenie może buforować  dane  i polecenie niekoniecznie natychmiast  zostanie wysłane. Zamknięcie  strumienia  Następnie należy otworzyć strumień wejściowy oczekiwać na odpowiedź serwera. Otwarcie strumienia wejściowego ma poniższą postać. OutputStream os = sc.openInputStream() ; Dane napływające to również ciąg bajtów o nieznanej długości. Jeżeli znany jest format danych przesyłanych przez serwer, to można skorzystać z przesyłanych informacji.  Można odczytać  pewną liczbę bajtów, należy pamiętać, że dane nie  muszą napływać w jednolitych porcjach. Dane można odczytać podobnie jak w poprzednim przykładzie. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

50 Przykład wykorzystania gniazda (Socketa):
String ulr= ”www.wp.pl” SocketConnection c = null; InputStream s = null; OutputStream os; try { c = (SocketConnection)Connector.open(url); s = c.openInputStream(); os = sc.openOutputStream(); //wyslanie zapytania, oczekiwanie na odebranie danych… } catch (ConnectionNotFoundException e) { // Połączenie nie może być zrealizowane } catch (IllegalArgumentException e) { //Błędne zapytanie } finally { if (s != null) s.close(); if (c != null) c.close(); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

51 Połączenia sieciowe w J2ME
- bluetooth © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

52 Składowanie danych w urządzeniach mobilnych przy wykorzystaniu J2ME
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

53 „Pamięć nieulotna” Midlety niekiedy muszą zapamiętywać i przechowywać informacje na stałe, są to dane wprowadzane przez użytkowników(np. dane konfiguracyjne aplikacji). Specyfikacja MIDP wymaga, by wszystkie urządzenia posiadały pamięć nieulotną, czyli taką, w której  będzie przechowywana informacja nawet wtedy, gdy midlet kończy swoje działanie lub w sytuacji, gdy urządzenie zostanie fizycznie wyłączone. W praktyce problem ten rozwiązywany jest różnie przez różne urządzenia, chociaż dla programisty nie ma to żadnego zdarzenia, ponieważ interfejs jest jeden. Informacje są przechowywane w  postaci kolekcji rekordów (record  store). Każda kolekcja rekordów jest identyfikowana przez nazwę, która jest rzecz jasna unikalna. Midlety dostęp mają jedynie do „swoich” kolekcji, nie mają za to dostępu do kolekcji rekordów innych Milletów. Nie mają również dostępu do danych utworzonych przez inne aplikacje. Sposób zapisu danych może być różny na różnych modelach u różnych producentów. Jednak dla J2ME został opracowany uniwersalny sposób dla wszystkich urządzeń o nazwie RMS - Record Management System. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

54 Nad zbiorami rekordów w J2ME czuwa klasa RecordStore.
Aby utworzyć jakiś zbiór należy wywołać jej statyczną metodę: public static RecordStore openRecordStore(String nazwa, boolean tryb) Pierwszy parametr określa nazwę zbioru (nazwa może być dowolna) Drugi parametr oznacza tryb dostępu / tworzenia do zbioru -Jeśli ustawiony jest na „true” wtedy, gdy w momencie próby otwarcia nie istnieje – zostanie utworzony nowy. W przypadku wartości „false” można otworzyć jedynie istniejący magazyn. W przypadku ,gdy nie istnieje – wyrzucany jest wyjątek. W MIDP 2.0 dodano dwie nowe metody openRecordStore o innych parametrach i bardziej specjalistycznych zadaniach. M.in. z ustawieniem uprawnień i przypisywaniem danego zbioru do konkretnego MIDletu. Metoda zwraca nam utworzony (lub otworzony) zbiór na którym możemy wykonywać operacje zapisu i odczytu. W razie błędów generowane są następujące wyjątki: RecordStoreNotFoundException - zbiór nie istnieje (w przypadku gdy nie ma być automatycznie utworzony) RecordStoreFullException - brak dostępnej pamięci IllegalArgumentException - błędna nazwa zbioru RecordStoreException - inny błąd © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

55 Po zakończeniu pracy z kolekcją można ją zamknąć :
Zatem: RecordStore store = RecordStore.openRecordStore(„ZbiorTestowy", true);       //wyrzuci wyjątek  „RecordStoreNotFoundException” jeśli zbiór nie istnieje   RecordStore secondStore = RecordStore.openRecordStore(„ZbiorTestowy", false); Po zakończeniu pracy z kolekcją można ją zamknąć : public static void closeRecordStore(); lub także skasować : public static void deleteRecordStore() ; // O tym w dalszej części wykładu © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

56 Metoda dodająca nowy rekord do magazynu :
Magazyn rekordów składa się z rekordów, które są tablicą bajtów. Każdy rekord ma przypisany identyfikator – jest to liczba całkowita dodatnia. Nie jest ona częścią rekordu, tylko jest przydzielana podczas dopisywania rekordu do magazynu. Gdy dana wartość zostanie raz przydzielona to nie może już zostać przydzielona żadnemu innego rekordowi, nawet w sytuacji ,gdy rekord ten zostanie usunięty z magazynu. Metoda dodająca nowy rekord do magazynu : public static int addRecord(byte[] dane,int od_którego,int ile) ; dodaje nowy rekord do zbioru i zwraca nam ID rekordu. Parametr pierwszy to dane do zapisu w postaci tablicy bajtów. Parametr drugi : od którego bajtu ma być zapisywane Parametr trzeci: ile bajtów ma zostać zapisanych. - void setRecord(int recordId, byte[] newData, int offset, int numBytes) ta metoda służy do zastąpienia rekordu nowym. Dodatkowym parametrem jaki trzeb podać jest ID rekordu który ma być zastąpiony, reszta jak powyżej. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

57 1. Tworzymy nowy magazyn :
Każdy rekord, jak wspomniano wyżej ,jest tablicą bajtów. Zatem aby umieść w nim jakieś dane, trzeba je najpierw zamienić na tablicę bajtów. Można to oczywiście przeprowadzić na wiele sposób, przykładowo za pomocą klas DataOutputStream i ByteArrayOutputStream. Przykład 1. Sposób zapisu rekordu 1. Tworzymy nowy magazyn : RecordStore nowy_magazyn = null; Klasa “Dane” będzie służyć to tworzenia obiektów zawierających dane do zapisu w magazynie class Dane{ String DaneTxt; int DaneNum; Dane(String a, int b){ DaneTxt = a; DaneNum = b; } } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

58 2. Zapisujemy dane do strumienia :
private byte[] zapiszStrumien(Dane przyklad) throws IOException { ByteArrayOutputStream bs = new ByteArrayOutputStream(); DataOutputStream os = new DataOutputStream(bs); os.writeUTF(przyklad.daneTxt); os.writeInt(przyklad.daneNum); return bs.toByteArray(); } 3. Zapisujemy dane w postaci strumienia do rekordu : private void zapiszRecord(Dane przyklad)throws IOException,RecordStoreException { try{ byte[] dane = zapiszStrumien(przyklad); id = nowy_magazyn.addRecord(dane,0,dane.length); }catch(Exception e){System.out.println(e); } } zmienna id (niezdefiniowana nigdzie w metodzie ‘zapiszRecord’ ) może służyć do wyświetlania identyfikatora nowego rekordu, jeśli jest to do czegoś potrzebne. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

59 Przydatną może okazać się tutaj metoda enumerateRecord():
Ważne jest aby zamykać strumień i zbiór, urządzenia mobilne nie posiadają dużo pamięci więc należy je oszczędzać (nie zamykanie strumieni może być jedną z przyczyn tzn. wycieków pamięci). Podczas każdej operacji addRecord, setRecord i deleteRecord na zbiorze inkrementowana jest jego wersja. Wersję zbioru można otrzymać poprzez wywołanie int getVersion(). Odczyt danych z rekordów można realizować na kilka sposobów, na przykład podając identyfikator rekordu w magazynie. Metoda to wykonująca wygląda następująco : byte[] dane = nowy_magazyn.getRecord(id); Jeśli nie znamy zbiorów MIDletu możemy pobrać ich nazwy za pomocą metody statycznej RecordStore.listRecordStores(); Zwraca ona tablicę Stringów lub null w przypadku gdy nie ma żadnego dostępnego zbioru. Przydatną może okazać się tutaj metoda enumerateRecord(): enumerateRecord(RecordFilter filtr, RecordComparator porownaj, boolean kontrolowac); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

60 Argument  RecordFilter filtr pozwala zdefiniować sposób wyboru rekordów z magazynu. Jest to interfejs wymagający określenia metody o nazwie matches() . Dzięki niemu można dokładnie ustawić jakie kryteria muszą spełnić rekordy, aby zostały odczytane, np. wybrać wszystkie rekordy (z przykładu przedstawionego wyżej, które zawierają liczbę dodatnią.) Podanie wartości null spowoduje, że rekordy odczytywane będą bez ograniczeń. Argument RecordComparator porownaj pozwala na uporządkowanie wg wybranego kryterium, np.: uporządkuj rosnąco według wartości liczb. Podanie wartości null spowoduje, że rekordy odczytywane będą kolejno zgodnie z natywną implementacją. Argument boolean kontrolowac pozwala na podjęcie decyzji , czy sposób odczytu rekordów (kryteria, kolejność) będą mogły się zmieniać za każdym razem, gdy nastąpi zmiana w magazynie. W takiej sytuacji zmianie musi ulec obiekt pozwalający na wyliczanie, jest to jednak dosyć czasochłonne. W przypadku, gdy ten parametr przyjmuje wartość false, należy budować na nowo obiekt enumerteRecord przy każdej zmianie. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

61 A oto przykład odczytu danych z magazynu, trzeba oczywiście pamiętać o zamianie danych z postaci tablicy bajtów do postaci oryginalnej: private Dane getDane(int id,RecordStore nowy_magazyn)throws IOException, RecordStoreException { byte[] dane = nowy_magazyn.getRecord(id); DataInputStream is = new DataInputStream( new ByteArrayInputStream(dane)); Dane przyklad2 = new Dane(is.readUTF(), is.readInt()); return przyklad2; } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

62 Poniżej przykład metody odczytującej dane z całego magazynu (ze wszystkich rekordów danego magazynu, przy wykorzystaniu metody enumerateRecord(); ) private String czytajMagazyn(String nazwa) throws Exception { RecordStore nowy_magazyn = null; int id; String ret; try{ nowy_magazyn = RecordStore.openRecordStore(nazwa,true); }catch(Exception e){ System.out.println("Blad Otwarcia magazynu!"); } RecordEnumeration wyl = nowy_magazyn.enumerateRecords(null,null,false); while(wyl.hasNextElement()){ id = wyl.nextRecordId(); Dane przyklad = getDane (id,spis); ret = id + " " + przyklad.daneTxt + " " + przyklad.daneNum; System.out.println(id + " " + przyklad.daneTxt + " " + przyklad.daneNum + "\n";); } try{ wyl.destroy(); nowy_magazyn.closeRecordStore(); }catch(Exception e){ System.out.println("Blad zamkniecia" + e); } return ret; } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

63 usuwa rekord o podanym ID ze zbioru
Na koniec usuwanie. Mamy do dyspozycji dwie proste metody: void deleteRecord(int recordID); usuwa rekord o podanym ID ze zbioru static void deleteRecordStore(String recordStoreName); usuwa cały zbiór rekordów o podanej nazwie. Ale uwaga - zbiór musi być zamknięty inaczej otrzymamy wyjątek RecordStoreException. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

64 Dystrybucja programów w J2ME
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

65 Programowanie i testowanie w Symbian OS
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

66 W jego skład wchodzą najwięksi producenci telefonów komórkowych: Nokia
Symbian to nazwa systemu operacyjnego, dołączonych do niego bibliotek, rozwiązań interfejsu użytkownika oraz specyfikacji dla programów narzędziowych wyprodukowanych przez konsorcjum Symbian. W jego skład wchodzą najwięksi producenci telefonów komórkowych: Nokia Samsung Motorola Siemens Sony Ericsson Symbian został stworzony w oparciu o system EPOC, wykorzystywany w PDA firmy Psion PLC. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

67 Obecnie licencje na wykorzystywanie systemu operacyjnego Symbian posiadają:
Arima BenQ Fujitsu Lenovo LG Matsushita Mitsubishi Motorola Nokia Samsung Sharp Siemens Sony Ericsson. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

68 EPOC jest rodziną systemów operacyjnych opracowanych przez firmę Psion przeznaczonych dla urządzeń przenośnych, przede wszystkim PDA EPOC16 EPOC16, początkowo nazywany po prostu EPOC. Jest to system operacyjny opracowanym przez Psion w późnych latach 80. i wczesnych 90. Powstał z myślą o dla urządzenia "SIBO" (SIxteen Bit Organisers). System ten pracował na platformach opartych o procesor Intel Jego architektura jest 16-bitowa, jest systemem operacyjnym przeznaczonym dla pojedynczego użytkownika, mogącym pracować w trybie wielozadaniowości (z wywłaszczaniem). Napisany został w dwóch językach: asemblerze oraz języku C i zaprojektowanym tak, aby mógłbyć umieszczony w pamięci ROM. Pierwsze urządzenia pod kontrolą EPOC16, zostały wypuszczone na rynek w 1989. W późnych latach 90. systemowi przypisano nazwę EPOC16, aby odróżnić go od nowego systemu operacyjnego jakim był EPOC32. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

69 System operacyjny EPOC32 został później przemianowany na Symbian.
EPOC32, Symbian OS Pierwsze wydanie EPOC32 (Release 1) pojawiło się w Series 5 ROM v1.0 w Powstało szybko wiele jego wersji. System operacyjny EPOC32 został później przemianowany na Symbian. EPOC32 i EPOC16 były zupełnie odmiennymi systemami operacyjnymi. EPOC32 napisany w języku C++, który był rozwijany w połowie lat 90. Jest systemem operacyjnym przeznaczonym dla pojedynczego użytkownika, mogącym pracować w trybie wielozadaniowości(z wywłaszczaniem). Posiada zabezpieczenie pamięci, zatem należy dzielić aplikacje na silnik i interfejs użytkownika. EPOC32 był początkowo przeznaczony dla rodziny procesorów ARM, włączając w to: ARM7, ARM9, StrongARM i XScale Intela, ale może być kompilowany w odniesieniu do urządzeń korzystających z innych typów procesorów. W czerwcu 1998, Psion Software stała się firmą Symbian Ltd., spółką joint venture pomiędzy Psion i wytwórcami telefonów: Ericsson, Motorola i Nokia. Jako wydanie szóste (Release 6), EPOC był już nazywany po prostu Symbian. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

70 Jakie możliwości daje SYMBIAN?
Symbian to system operacyjny dla telefonów komórkowych. Pozwala zmienić zwykły telefon komórkowy w urządzenie wielofunkcyjne. użytkownik może dowolnie korzystać z dodatkowego oprogramowania. Umożliwia m.in. korzystanie z internetu [przeglądanie stron www, poczta elektroniczna, ftp, komunikatory internetowe etc.], przeglądanie i edycję dokumentów word, excel czy pdf, odtwarzanie i nagrywanie muzyki, fotografowanie i edycję zdjęć, nagrywanie i odtwarzanie video [włącznie z formatami typu DivX, Xvid, AVC], nawigację GPS, zapewnia również rozrywkę poprzez wiele różnego rodzaju gier. Żeby móc korzystać z dobrodziejstw Symbiana trzeba kupić telefon oparty na tym systemie. Urządzenia te dzielą się ze względu na interfejs użytkownika. S60 Dzieli się na 4 edycje. S60 1 edycji S60 2 edycji S60 3 edycji S60v3 dodatkowo dzieli się na wersje FP1 (Feature Pack 1) i FP2 (Feature Pack 2). Więcej informacji w artykułach: S60 5 edycji UIQ - aktualnie nie rozwijany(telefony z ekranem dotykowym). Dzieli się na 2 edycje. UIQ 2 edycji UIQ 3 edycji Series80 - Nokia - urządzenia typu Communicator z pełną klawiaturą QWERTY - aktualnie nie rozwijany Series90 - Nokia - tablety internetowe - aktualnie nie rozwijany NTT DoCoMo's MOAP - FOMA - dostępny tylko w Japonii © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

71 Programowanie pod Symbian :
Wspieranie języki : C++ Java Pyhton Środowiska Programistyczne (Przykłady): Carbide C++ Express NetBeans (Java, C++) Eclipse (Java) Java – Sytuacja podobna jak w przypadku większości innym platform, wykorzystujących J2ME. Symbian C++ Termin Symbian C++ odnosi się do specyficznej odmiany języka C++, wraz z towarzyszącymi mu Frameworkami używanymi przez Symbiana. Symbian C++ znacząco różni się od powszechniejszego C++, związane jest to z platformami, jak również i doświadczenia z przeszłości (Symbian jest przecież kontynuacją systemu operacyjnego EPOC firmy Psion, którego pierwsze wersje powstały w latach 80.). Różnice pomiędzy „Standardowym” C++, a Symbian C++ są duże. Przykładem jest zupełnie inny mechanizm wyjątków. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

72 Symbian C++ - krótkie wprowadzenie
Symbian C++ jest językiem bardzo restrykcyjnym. Wynika to z bardzo ograniczonych zasobów (w stosunku np. Do komputerów PC). Twórcy starali się standaryzować wszystko, włączanie z odpowiednim nazewnictwem w kodzie. A wszystko to między innymi, aby uniknąć błędów (np. wycieków pamięci). Nazwę typu poprzedza duża litera T (od Type), zmienne które odpowiadają unsigned - posiadają przed nazwą typu (po T) dużą literę U (od unsigned): TInt8, TUInt8 – zmienna całkowita 8-bitowa oraz jej odpowiednik typu unsigned TInt16, TUInt16 – analogicznie j.w., ale 16-bitowa TInt32, TUint32 – j.w., ale 32-bitowa (TInt, TUInt) TInt64 – zmienna całkowita 64-bitowa, w praktyce przechowywana jako 2 zmienne 32-bitowe TReal32 – zmienna zmiennoprzecinkowa o podwójnej precyzji 32-bitowa TReal, TReal64 – j.w., ale 64-bitowa TText8, TText16 – zmienne tekstowe (odpowiednikami w C++ są odpowiednio – unsigned char oraz unsigned short int) TBool – zmienne booleanowskie TAny – odpowiednik void z C++, najczęściej używany jako TAny * © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

73 Kiedy funkcja może wyjść (leave’ować). 1
Kiedy funkcja może wyjść (leave’ować)? 1. Funkcja może wychodzić, gdy zawiera w sobie inne funkcje mogące wychodzić, czyli oznaczone L na końcu. Gdy wykorzystujemy jakąś funkcje leave’ującą, oznacza to że nasza funkcja także może leave’ować, a więc musimy oznaczyć ją literką L. 2. Możemy także programowo wywołać leave’owanie, wywołując statyczną metodę User::Leave //lub którąś z jej wersji. Mamy do wyboru: User::Leave(jakiś_błąd); //Leave jest wywołany, jeżeli wystąpi jakiś_błąd. Przykład: User::Leave(KErNoMemory); W tym momencie program wyjdzie, jeżeli zabraknie pamięci. User::LeaveNoMemory() //funkcja wychodzi, gdy jest brak pamięci,odpowiednik funkcji poprzedniej User::LeaveIfNull() – funkcja wychodzi jeżeli zwrócony wskaźnik jest NULL. User::LeaveIfError() – czyli gdy wywoływana funkcja zwróci nam błąd. Przykład (łączenie się z serwerem plików): User::LeaveIfError(iFs.Connect()); W tym momencie jeżeli poprawnie połączymy się z serwerem plików, program pójdzie dalej. Jeżeli jednak wystąpi jakiś błąd – zrobimy Leave. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

74 Nazwy klas (prefiksy):
T – typy Klasy T nie posiadają destruktora, występują w sposób jak typy wbudowane. C – klasy Klasy C to klasy dziedziczące po CBase. M – interfejsy (Mixin) Klasy M są interfejsami składającymi się z funkcji wirtualnych. Nazwy danych (prefiksy) E – stałe typów wyliczeniowych Stała typu wyliczeniowego, powinna być składową stałej o nazwie rozpoczynającej się od T K – stałe i – zmienne składowe Każda nie-statyczna zmienna składowa (i od instance). a – argumenty Wszystkie zmienne deklarowane jako argumenty. Nazwy funkcji (sufiksy) L – funkcje, które mogą leaveować (leaveowanie zostanie wyjaśnione później). C – funkcje, które zostawiają coś na Cleanup Stacku (Cleanup Stack zostanie wyjaśniony później). Nazwy makr Pisane dużymi literami, podkreślenia zamiast spacji. Symbole wbudowane Pisane z podwójnym podkreśleniem jako prefiks oraz sufiks. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

75 W przypadku zmiennych boolean prawda oraz fałsz programowo są oznaczane odpowiednio jako ETrue oraz EFalse. : TBool b= Etrue; if (b == ETrue) { ... } Tutaj mała uwaga – w C++ wszystko co nie jest zerem uznawane jest za prawdę, natomiast w Symbian C++ ETrue odpowiada za wartość 1. TBool b = Funkcja(); if (b) { ... } Otóż wszyscy programiści C++ na pewno mają na uwadze różnice w rozmiarze typów zmiennych w przypadku różnych platform i/lub różnych kompilatorów. Z uwagi, że pisząc aplikacje na Symbian OS należy uwzględnić różne telefony (również kompilatory, środowiska), stosując typy zmiennych zaprezentowane w liście powyżej mamy pewność, iż zawsze będą takie jakie mają być. Jedynym odstępstwem od tej reguły jest zwracany typ void przez funkcje (w przypadku deklarowania wskaźników typu pustego, należy posługiwać się typem TAny). © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

76 Prototyp funkcji wygląda jak pokazano poniżej:
Od Symbian OS 8.1 możliwe jest użycie mechanizmów przechwytywania wyjątków znanych z języka C++, chociaż takie podejście do sprawy nie jest zalecane. Twórcy systemu namawiają do pozostania przy bardziej przetestowanym, bogatszym i zaimplementowanym w systemie od pierwszej wersji mechanizmie walki z błędami. Błędy Panics W momencie powstawia bledu system najlepsze co moze zrobic , to zamknac aplikacje. Podstawową używaną tutaj funkcją jest User::Panic(panicCategory, integer), gdzie panicCategory powinien być maksymalnie 16 znakowym określeniem błędu, integer natomiast 32-bitowym numerem błędu. Powszechnym sposobem używania Panics jest użycie makr __ASSERT_DEBUG oraz __ASSERT_ALWAYS; pierwszy jest kompilowany w wersji Debug, drugi w wersji Debug jak również i przy kompilowaniu wersji finalnej. Poniższy przykład obrazuje użycie opisanych makr: void CMyClass::Foo(TInt aIndex) { __ASSERT_ALWAYS (aIndex > 0, Panic(_L("Błąd typu Panic"), 11)); } Prototyp funkcji wygląda jak pokazano poniżej: __ASSERT_ALWAYS(warunek, wyrażenie); Kiedy to wyrażenie jest wykonane gdy warunek nie jest prawdą. W tym przypadku Panic zostanie wywołane gdy aIndex będzie wartością mniejszą bądź równą zero, natomiast błąd zwrócony będzie treści „Błąd typu Panic” (_L() musi być używane do przekazywania własnych treści. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

77 TRAPD –zajmuje się od razu deklaracją zmiennej; przykład użycia TRAPD:
Mechanizm Leave służy do wychodzenia z funkcji, natomiast TRAP oraz TRAPD do przechwytywania tych wyjść, przy czym używanie przechwytywania nie jest zalecane ze względu na ich szybkość (a raczej nie-szybkość) działania oraz pamięciożerność. TRAP TInt err; TRAP(err, funkcjaL()); TRAP(D) TRAPD –zajmuje się od razu deklaracją zmiennej; przykład użycia TRAPD: TRAPD(err, funkcjaL()); oraz przykład użycia TRAP TInt err; TRAP(err, funkcjaL()); Jak widać, w przypadku wersji TRAPD kod skraca się o jedną linijkę. Warto tutaj zauważyć, iż w przypadku gdy nie zastosujemy żadnego przechwycenia w programie, system zrobi to za nas. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

78 User::Leave(kodBłędu)
Mechanizm leave jest pewnym odpowiednikiem wyjątków z „normalnego” C++. Służy określeniu miejsc w programie, gdzie coś może pójść nie tak nie z winy programisty. Są to na przykład funkcje, w których alokujemy pamięć. Programista nie może wiedzieć, czy pamięć jest akurat dostępna. Jeżeli tak – wszystko w porządku. Jeżeli nie – funkcja leave’uje. Funkcje które mogą leave’ować oznaczane są dużą literką L na końcu. Nie jest to tylko kosmetyka. User::Leave() Wyjście z funkcji User::Leave(kodBłędu) Wyjście z funkcji z kodem błędu (jest przekazywany do TRAP(D)) User::LeaveIfError(kodBłędu) Wyjście z funkcji tylko w przypadku gdy kodBłędu jest negatywny (mniejszy od 0, wszystkie błędy są wartościami ujemnymi) User::LeaveNoMemory() Odpowiednik User::Leave(KErrNoMemory) User::LeaveIfNull(wskaźnik) Wychodzi z funkcji z KErrNoMemory jeśli przekazany wskaźnik jest NULL © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

79 Oraz jak to wygląda z CleanupStack:
Należy zwrócić uwagę co się dzieje ze wszystkimi wskaźnikami, które zostały zainicjowane przed takim wyjściem – otóż jeżeli zostanie on usunięty, natomiast miejsce w pamięci nadal jest zajęte. Miejsce w pamięci nadal jest zajęte, jednak nie mamy do niego już dostępu - następuje wyciek pamięci. CleanupStack CleanupStack wykorzystywany jest, gdy po zaalokowaniu pamięci na dany obiekt, funkcja może wywołać Leave nie dochodząc do momentu w którym uprzednio stworzony obiekt jest poprawnie usuwany. Przykład użycia: void JakasKlasa::FunkcjaL() { TInt * liczba = new (ELeave) TInt; //tutaj może dojść do wycieku pamięci… delete liczba; } Klasa * nowy_obiekt = new (ELeave) Klasa; // tu może coś nie wyjść… Nowy_obiekt->Funkcja(); delete nowy_obiekt; Oraz jak to wygląda z CleanupStack: Klasa * nowy_obiekt = new (ELeave) Klasa; CleanupStack::PushL(nowy_obiekt); Nowy_obiekt->FunkcjaL(); CleanupStack:PopAndDestroy(nowy_obiekt); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

80 Istnieje kilka wariacji funkcji zdejmujących z CleanupStack:
W takim przypadku, od razu po alokacji pamięci dla obiektu w następuje zachowanie tego wskaźnika na CleanupStack. W momencie, gdy Funkcja() zakończy swe działanie nie powodując żadnego błędu, funkcja CleanupStack::PopAndDestroy(nowy_obiekt) zdejmuje ten wskaźnik od razu go niszcząc, oraz usuwane przydzielone mu zasoby. Natomiast jeżeli Funkcja() wyjdzie, wtedy jako część procesu czyszczenia wszystkie obiekty znajdujące się na CleanupStack są poprawnie usuwane. Istnieje kilka wariacji funkcji zdejmujących z CleanupStack: CleanupStack:Pop() – zdejmuje ze stosu ostatnio położony wskaźnik CleanupStack:Pop(2) – zdejmuje ze stosu ostatnie dwa położone wskaźniki CleanupStack:Pop(wsk) – zdejmuje ze stosu i sprawdza czy jest to wsk CleanupStack::PopAndDestroy(); oraz CleanupStack::PopAndDestroy(wskaźnik); Funkcja zdejmuje wskaźnik do obiektu i od razu go niszczy (czyli wywołuje delete na obiekcie, który ten wskaźnik pokazuje). CleanupStack::PushL(wskaźnik); - odkładanie wskaźników. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

81 Nie odkładamy składowych klas na CleanupStack
Nie odkładamy składowych klas na CleanupStack. Dlatego, że składowe klasy niszczymy w destruktorze tej klasy, który będzie wywołany kiedy ta klasa będzie niszczona. Jeżeli odłożymy taką zmienną, system będzie chciał zniszczyć obiekt dwa razy – pierwszy, bo będzie miał wskaźnik na stosie, a drugi raz gdy będzie niszczył klasę w destruktorze. -Podsumowując wskaźniki do obiektów odkładamy na stos wtedy, kiedy między stworzeniem obiektu a jego zniszczeniem nie mamy gwarancji, że program na pewno nie wyjdzie. Jeśli takiego zagrożenia nie ma – nie ma potrzeby stosowania tego mechanizmu. Tak więc że nie zawsze musimy odkładać na stos wszystkiego, co tworzymy     Zatem Nie należy nadużywać tego mechanizmu i kłaść na CleanupStack tylko te wskaźniki, w których pomiędzy stworzeniem a usunięciem może wystąpić Leave. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

82 Programowanie i testowanie w Microsoft Mobile ASP.NET
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

83 Rozwój oprogramowania
Systemy operacyjne urządzeń mobilnych © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

84 Windows CE – system operacyjny opracowany przez Microsoft jako system dla urządzeń przenośnych typu PDA (np.: Pocket PC lub Palm) lub jako system wbudowany. Wersja 1.0 była bardziej rozbudowanym organizerem niż systemem operacyjnym (z punktu widzenia użytkownika.) Windows CE jest zoptymalizowany dla urządzeń o minimalnej pamięci – jądro Windows CE może być uruchomione nawet w 1 MB pamięci. System nie wymaga d pracy dysku twardego, może być więc „system zamkniętym”, i być umieszczony w pamięci ROM. Obsługuje 256 priorytetów wykonywania i korzysta z dziedziczenia priorytetów w razie, przydatnych w sytuacji inwersji piorytetów. Podstawową jednostką wykonywania jest wątek, co umożliwia prostsze zarządzanie procesami. Windows CE używany jest także w komputerach pokładowych samochodów wraz z systemem rozpoznawania mowy mającym zapewnić bezdotykową obsługę systemu operacyjnego. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

85 Windows CE 1.x specyfikacja urządzeń na których system miał pracować :
Wymiary nie większe niż 18x10x2.5 cm Zasilanie z dwóch baterii AA Waga mniejsza niż 500 g Klawiatura QWERTY zawierająca klawisze takie jak SHIFT, CTRL i ALT Dotykowy wyświetlacz LCD o rozdzielczości 480x240 pikseli w 4 odcieniach szarości Minimum 4 MB pamięci ROM Minimum 2 MB pamięci RAM Port podczerwieni Port COM zgodny z RS-232 Slot PC Card (PCMCIA) Wbudowana obsługa dźwięku Procesor SuperH 3, MIPS 3000 lub MIPS 4000 Microsoft nie wypowiedział się jednoznacznie co oznacza skrót CE, lecz twierdzi, że taka nazwa nie była celowa. Oświadczył jednak, że CE wyrażać może w sobie wiele koncepcji, takich jak Compact (ang. Kompaktowy), Connectable (ang. Łącznościowy), Compatible (ang. Kompatybilny). Najczęściej jednak nazwę tłumaczy się jako "Compact Edition" lub "Consumer Electronics". © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

86 Wygląd GUI systemu Windows CE 1.0
Źródło: Internet. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

87 10 Windows Mobile (i ten system również posiada kilka wersji.)
Wersje systemu 1 Windows CE 1.x 2 Windows CE HandheldPC 2.x 3 Windows CE Palm-Size PC Windows CE Palm-Size PC Windows CE HandeldPC HandheldPC Professional 6 Windows CE HandeldPC 3.x - HandheldPC Windows CE .net (4.x) 8 Windows CE Windows CE 6.0 10 Windows Mobile (i ten system również posiada kilka wersji.) Od wersji 4.0 z systemem zintegrowano .NET Compact Framework. Windows CE 6.0 powstał we wrześniu 2006 roku. Nazwa kodowa "Yamazaki". M.in. zwiększono przestrzeń adresową procesu z 32 MB do 1 GB i umożliwiono uruchomienie procesów (w porównaniu z 32 w wersji 5.0). © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

88 Microsoft Windows Mobile
Microsoft Windows Mobile to 32-bitowy system operacyjny przeznaczony dla urządzeń typu Pocket PC oraz Smartphone. Windows Mobile nie jest zupełnie osobnym systemem, lecz rozszerzeniem Windows CE o dodatkową funkcjonalność, API (ang. Application Programming Interface) oraz Shell. Dostępne wersje Systemu: Windows Mobile 2003 Windows Mobile 2003SE Windows Mobile 5.0 Windows Mobile 6.0 (64 MB RAM, wyświetlacz 3,5 cala) Windows Mobile 6.1 Classic Istnieją wersje przeznaczone dla PocketPC z wbudowanym modułem GSM: Windows Mobile 2003 Premium Phone edition Windows Mobile 2003SE Phone edition Windows Mobile 5.0 (Magneto) Phone edition Windows Mobile 6.0 Phone edition Windows Mobile 6.1 Professional Windows Mobile 6.5 Professional Windows Mobile Professional (w trakcie rozwoju) Windows Mobile 7 Professional (w trakcie rozwoju) © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

89 Wygląd GUI systemu Windows Mobile 5.0
Istnieją również wersje dla smartphone obsługujące ekrany 176x220 oraz 240x320 bez ekranu dotykowego: Smartphone 2002 Windows Mobile 2003 for Smartphone Windows Mobile 2003SE for Smartphone Windows Mobile 5.0 for Smartphone Windows Mobile 6.0 for Smartphone Windows Mobile 6.1 Standard Wygląd GUI systemu Windows Mobile 5.0 Źródło: Internet. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

90 .NET Compact Framework Platforma umożliwiająca uruchamiane aplikacji napisanych w językach rodziny .NET, bedaca swego rodzaju maszyną wirtualną (jak np. JVM). Zatem można powiedzieć, że .Net Framework to maszyna wirtualna udostępniająca biblioteki, odpowiedzialne za nisko-poziomową interakcję z systemem operacyjnym, językom zarządzanym (ang. managed) wysokiego poziomu, np. C#. Kod napisany w C# czy J# jest najpierw kompilowany do pośredniego języka MSIL (Microsoft Intermediate Language). Wynikiem tego działania jest moduł zawierający instrukcje MSIL. Jedną z przyczyn zastosowania MSIL jest mozliwość wykorzystywania wielu języków programowania (VB, C#, J#, JScript, i Visual C++), skąd pojawia się konieczność pośredniej kompilacji kodu do MSIL. Następnie, moduł ten zamieniany jest na natywne instrukcje danego systemu operacyjnego CLR (ang. Common Language Runtime). Zatem .Net Framework postrzegać powinno się bardziej, jako platformę wielojęzykową, a nie jak maszynę wirtualną (jak np. maszyna wirtualna Javy) – wieloplatformową. Przeprowadzane są obecnie prace nad rozszerzeniem owych pięciu wspieranych języków programowania do ponad dwudziestu pięciu . © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

91 Architektura .NET Compact Framework
Źródło: Internet © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

92 CLR składa się z dwóch zasadniczych elementów:
Common Language Runtime – wspólne środowisko uruchomieniowe. Jego podstawowym zadaniem jest zlokalizowanie, wczytywanie oraz zarządzanie typami .NET w imieniu użytkownika. CLR zajmuje się niskim poziomem pracy aplikacji np.: automatyczne zarządzanie pamięcią, integracją językową oraz ułatwianie wdrożenia ( i wsparcie dla różnego rodzaju wersji ) bibliotek kodu binarnego. CLR składa się z dwóch zasadniczych elementów: Runtime execution engine - mechanizm wykonawczy środowiska uruchomieniowego – mscoree.dll. Kiedy pakiet ( assembly ) jest wywoływany, automatycznie wczytywany jest mscoree.dll, który z kolei wczytuje do pamięci potrzebny pakiet. Mechanizm uruchomieniowy jest odpowiedzialny za wykonanie szeregu zadań. Pierwszym i najważniejszym jest określenie położenia pakietu i znalezienie wymaganego typu ( np. klasy, interfejsu, struktury itp. ) w kodzie binarnym przez odczytanie dostarczonych metadanych. Mechanizm wykonawczy kompiluje zasocjowany IL ( Intermediate Language ) do instrukcji specyficznych dla danej platformy. Biblioteka klas podstawowych. Składa się z kilku oddzielnych pakietów, najważniejszym jest mscorlib.dll. Zawiera dużą liczbę podstawowych typów, które hermetyzują dużą różnorodność najczęściej spotykanych zadań programistycznych. Każde rozwiązanie oparte na platformie .NET, zawsze wykorzystuje się ten pakiet i czasem kilka innych .NET ( zarówno oferowanych przez system jak i przygotowanych przez użytkownika ). Common Language Specification – specyfikacja wspólnego języka. Jest zbiorem zasad definiujących podzbiór wspólnych typów (dla różnych języków), który daje pewność, że kod binarny .NET może zostać bez klejenia wykorzystany przez wszystkie języki współpracujące na platformie .NET. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

93 Common Type System – zbiór wbudowanych podstawowych i wspólnych typów
Common Type System – zbiór wbudowanych podstawowych i wspólnych typów. Zawiera pełny opis wszystkich możliwych typów danych, obsługiwanych przez środowisko uruchomieniowe. Zawiera także informacje, o tym, jakie interakcje mogą zachodzić między nimi, oraz określa szczegóły ich reprezentacji w formie metadanych .NET. Managed Code - Kompilatory zgodne z CLR zamieniają kod źródłowy aplikacji na kod wykonywalny, zapisany w standardowym języku pośrednim MSIL, oraz na metadane — informacje na temat kodu wykonywalnego oraz danych wykorzystywanych przez ten kod. Platforma .NET umożliwia pisanie aplikacji w wielu językach, ale dzięki MC kompilator zamienia wszystkie operacje na typach danych, to jest klasach, strukturach, liczbach całkowitych, łańcuchach znaków — na język MSIL i metadane. W czasie wykonywania aplikacji, CLR tłumaczy kod MSIL na kod maszynowy (natywny) procesora, na którym wykonywana jest aplikacja. Taka konwersja kodu z MSIL na kod maszynowy daje możliwość zarządzania wykonywaniem aplikacji, co pozwala uniknąć wielu problemów — stąd nazwa ”kod zarządzany”. Garbage Collection – .NET Compact Framework zapewnie zwalnianie wszystkich zasób, z jakich korzysta aplikacja, po jej zakończeniu. W tym celu wykorzystywany jest mechanizm o nazwie Garbate Collection. Compact Framework decyduje kiedy powinien zostać uruchomiony proces Garbate Collection. Może on zostać uruchomiony w pojedynczej domenie aplikacji bądź też we wszystkich dostępnych. Pozwala to zapobiegać sytuacją, gdy jedna aplikacja zużywa zbyt dużo pamięci w porównaniu z innymi. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

94 Class Library Support Klasy są zorganizowane hierarchicznie wewnątrz przestrzeni nazw ( namespace ). .NET Compact Framework współdzieli około 2/3 klas z pełną wersją .NET Framework. Mimo to występują pomiędzy nimi pewne istotne różnice, i trzeba być tego świadom podczas tworzenia aplikacji z wykorzystaniem .NET Compact Framework. Klasy współdzielone: .NET Compact Framework dostarcza szeroki podzbiór klas i metod do budowania aplikacji, które są później uruchamiane na urządzeniach z ograniczonymi zasobami. Wszystkie te klasy są semantycznie kompatybilne z klasami o tych samych nazwach w .NET Framework. .NET Compact Framework posiada wsparcie dla istotnych elementów takich jak: ·         Usługi sieci Web oparte na XML ·         Zarządzanie relacyjnymi danymi ·         Rozbudowana funkcjonalność XML ·         Rozbudowane klasy do rysowania, takie jak Image Controls ·         Potężne możliwości budowania interfejsu użytkownika. .NET Compact Framework nie wspiera klas ASP .NET. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

95 Klasy tylko dostępne w Compact Framework:
Podczas tworzenia aplikacji z wykorzystaniem .NET Compact Framework należy pamiętać o klasach dostępnych jedynie w tym środowisku. Chodzi np. o klasę Infrared Data Association ( IrDA ) do nawiązywania połączeń do serwera i dostarczania informacji o porcie podczerwieni. Kolejnym przykładem jest klasa SQL Server CE, która pozwala na pracę z lokalnym serwerem bazy danych SQL Server CE. Narzędzie Class Library Comparison Tool – pozwala na przeglądanie różnic między klasami dostępnymi w .NET Framework i Compact Framework. Dla każdej klasy można sprawdzić, które pola, metody i właściwości są dostępne w obydwu lub też w jednym z nich. Wiele z klas dostępnych w .NET Framework nie jest dostępnych w Compact Framework. Powodem tego są ograniczenia co do zasobów i wydajności urządzeń mobilnych. CLR dla .NET Compact Framework stanowi około 12 % rozmiaru całego .NET Compact Framework. Rozmiar ten jest ograniczony, po to aby zwiększyć wydajność. Pomimo braku wsparcia dla GDI+ Compact Framework obsługuje podstawowe rysowanie GDI takie jak: bitmapy, pędzle, pióra, czcionki i ikony. Compact Framework nie pozwala na tworzenie nowych usług sieci Web, ale umożliwia wykonywanie istniejących usług sieci Web. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

96 - Data – podzbiór implementacji ADO .NET oraz SQL Server CE
Dalsze różnice: ·         - COM Interop – nie wspierane, należy wykonywać funkcje DLL, które wywołują obiekty COM - Data – podzbiór implementacji ADO .NET oraz SQL Server CE - ASP .NET – nie wspierany. Należy używać ASP .NET Mobile Web Controls do tworzenia stron sieci WWW dla urządzeń przenośnych - XML – ze względu na rozmiar brak obsługi walidacji XML schema lub zapytań XPath w dokumentach XML. - Aby zmniejszyć rozmiary środowiska zrezygnowano z wielu przeładowanych metod - Brak niektórych kontrolek ( np. wsparcia dla drukowania ) - Ze względu na wydajność brak klas BinaryFormatter i SoapFormatter - Bezpieczeństwo – brak zabezpieczenia dostępu do kodu niezarządzanego. Dowolna aplikacja może wywołać dowolny system lub nie systemowe API. Brak systemu bezpieczeństwa opartego na rolach © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

97 W tablicach .NET Compact Framework nie zwraca wyjątku MissingMethodException;
Możliwość pisania aplikacji ASP .NET za pomocą kontrolek przeznaczonych dla urządzeń mobilnych; Możliwość stosowania assemblies (bez używania wielu modułów w .NET Compact Framework); Common Language Runtime oraz kompilacja Just-In-Time (JIT) są używane przed obydwa framework’i; .NET Compact Framework dziedziczy większość kontrolek używanych do pisania aplikacji Windows Forms; .NET Compact Framework nie ma metod GetCurrentDirectory oraz SetCurrentDirectory. Zamiast tego programista powinien używać właściwości WorkingDirectory oraz obiektu ProcessStartInfo; Aplikacje na .NET Compact Framework można pisać z wykorzystaniem C# lub Visual Basic. Aktualnie C++ nie jest wspierany; © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

98 Platformy, narzędzia i technologie
Smart Device Extensions (SDE) for Microsoft Visual Studio .NET – tworzenie aplikacji, które w całości działają na urządzeniach przenośnych. SDE rozszerza funkcjonalność Microsoft Visual Studio o tworzenie aplikacji na różnego rodzaju urządzenia mobilne przy czym pozwala wykorzystać praktycznie wszystkie dostępne możliwości Visual Studio. Stwarza to jedno środowisko do tworzenia aplikacji na urządzenia przenośne, komputery PC i serwery. SDE pozwala na projektowanie, debugowanie i wykonywanie aplikacji na wielu z dzisiejszych urządzeń mobilnych. SDE zawiera ponadto kilka dobrym, ekranowych emulatorów dla urządzeń przenośnych. Dostępne są emulatory dedykowane dla Pocket PC, Pocket PC 2002, Smart phones i dla urządzeń działających pod kontrolą systemu Windows CE .NET. Microsoft Mobile Internet Toolkit (MMIT) – służy do tworzenia aplikacji, których kod wykonywany jest na serwerze. W takich aplikacjach po stronie serwera mamy Microsoft SQL Server oraz Microsoft Information Services ( IIS ). MMIT pozwala na łatwe tworzenie złożonych aplikacji Webowych, których docelową (kliencką) platformę stanowią urządzenia mobilne. Dzięki temu rozwiązaniu pisanie oprogramowanie na urządzenia mobilne staje się proste i wydajne. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

99 MMIT dostarcza wszelkich korzyści projektowania aplikacji z pomocą ASP
MMIT dostarcza wszelkich korzyści projektowania aplikacji z pomocą ASP .NET. Ponadto MMIT posiada następujące udogodnienia: - Wsparcie dla szerokiej gamy urządzeń. Pozwala na używanie ASP .NET na wielu urządzeniach mobilnych, począwszy na telefonach komórkowych, skończywszy na urządzeniach Pocket PC. - Strony WWW stworzone z wykorzystaniem MMIT są tak samo prezentowane na wszystkich wspieranych urządzeniach, nie trzeba jej dostosowywać do poszczególnych urządzeń. Można tworzyć złożoną aplikację wykorzystując zbiór mobilnych kontrolek serwerowych bez żadnej wiedzy na temat WML-a lub innych podobnych języków. Środowisko uruchomieniowe bierze na siebie odpowiedzialność za różnice w implementacjach pomiędzy różnymi przeglądarkami, urządzeniami i bramkami sieciowymi. - Możliwość personalizacji i rozszerzania funkcjonalności. MMIT dostarcza takie same możliwości personalizacji i rozszerzalności jak ASP .NET. W dodatku narzędzie pozwala na dodawanie obsługi nowych urządzeń, bez konieczności jakiejkolwiek zmiany w kodzie aplikacji. Dzięki temu można mieć pewność, że aplikacja stworzona dzisiaj będzie w przyszłości działała na nowej generacji urządzeń. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

100 Możliwości programistyczne w Windows Mobile 5.0
Windows Mobile 5.0 zapewnia programistom nowe, liczne interfejsy programistyczne. Dzięki nim, programista może się skupić na konkretnych celach aplikacji, a nie sposobach ich realizacji. Elementy wspomaganie przez interfejsy to np.: rysowanie 2D i 3D, dostarczają nowych możliwości komunikacyjnych oraz ułatwiają obsługę elementów sprzętowych takich jak kamera czy też system nawigacji satelitarnej. Inne usprawnienia to m. in. : Nowe interfejsy API dostarczają wielu nowych możliwości np.: zarządzanie obrazami, kontaktami, Większa przenośność kodu i aplikacji pomiędzy urządzeniami Pocket PC a Smartphone. Nowe API do śledzenia aktywności systemu takich jak: zmiany w połączeniu z siecią, odbiór wiadomości SMS lub nadejście połączenia telefonicznego; Rozbudowane narzędzia do testowania aplikacji w zależności od orientacji ekranu, rozdzielczości czy też rodzaju urządzenia – przyspieszają tworzenie aplikacji w Visual Studio. API do obsługi wbudowanego aparatu. Windows Media Player 10Mobile pozwala na łatwa dołączenie multimediów do tworzonej aplikacji (np. wbudowanie odtwarzacza multimedialnego). Obsługa Direct3D dostarcza możliwości tworzenia aplikacji trójwymiarowych. Obsługa DirectDraw zapewnia większą kontrolę i elastyczność w aplikacjach 2D. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

101 Windows Mobile 5.0 posiada zainstalowane domyślnie w pamięci ROM środowisko .NET Compact Framework 1.0 wraz z SP3. Możemy wyróżnić trzy rodzaje API: - Nowo dodane API kierowane do programistów tworzących aplikacje w kodzie natywnym; - Istniejące wcześniej natywne API, ale teraz dodatkowo dostępne dla programistów kodu zarządzanego; - Nowo dodane API dostępne zarówno dla programistów kodu natywnego jak i zarządzanego. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

102 Podstawy działa Garbage collection
Garbage collection (zbieranie nieużytków) to architektura zarządzania pamięcią, w której proces zwalniania nieużywanych jej obszarów odbywa się automatycznie. Mechanizm taki stosuje się na przykład w wysokopoziomowych językach programowania, przy czym za jego obsługę nie odpowiada sam język, lecz wirtualna maszyna. Garbage collection zostało wymyślone przez Johna McCarthy'ego około roku 1959 do rozwiązania problemu ręcznego zarządzania pamięcią w Lispie. Był to pierwszy język obsługujący ten mechanizm. Przykładowymi językami obsługującymi ten mechanizm są Smalltalk, Python, Ruby, Java, C#. Istnieje co najmniej kilka metod pracy GC. Liczenie odnośników (reference counting) W tej metodzie każda jednostka zarezerwowanej pamięci ma licznik, w którym jest zapisana liczba odwołań do tej jednostki. Za każdym razem, kiedy dodajemy odwołanie, zwiększamy licznik we wskazywanej jednostce, a kiedy odwołanie usuwamy, zmniejszamy licznik. Jeśli wartość licznika osiągnęła zero, to usuwamy wszystkie odnośniki wychodzące z tego obszaru pamięci i zwalniamy go. Metoda ta nie gwarantuje zwolnienia wszystkich niepotrzebnych obszarów w sytuacji, gdy występują tzw. wzajemne (cykliczne) odwołania. Przykładowo, jeśli X zawiera wskaźnik na Y, a Y zawiera wskaźnik na X (np. są to dwa komunikujące się ze sobą obiekty), licznik w żadnym z nich nigdy nie osiągnie zera. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

103 Mark and Sweep jest obecnie najpopularniejszą metodą.
W liczeniu odnośników dodatkowe obliczenia związane z pracą kolektora nieużytków są rozłożone w czasie, gdyż wszystkie operacje muszą dbać o liczniki, co może skutkować znacznie mniejszym - lub też przeciwnie - znacznie większym, obciążeniem w porównaniu z innymi metodami. Mark and Sweep. W tej metodzie każda jednostka pamięci zawiera pojedynczy bit, który jest na początku czysty. Kiedy maszyna wirtualna przechodzi w fazę "garbage collection", zaczyna sprawdzać obiekty, o których wie, że istnieją do nich odwołania, zaznacza w nich ten bit i rekursywnie przechodzi przez wszystkie komórki przez nie wskazywane. Kiedy już wszystko zostało oznaczone, komórki bez znacznika są zwalniane, bo na pewno nic na nie nie wskazuje, po czym znacznik jest czyszczony wszystkim komórkom. Mark and Sweep jest obecnie najpopularniejszą metodą. Garbage collection przez kopiowanie Ta metoda polega na tym, że wszystko zostaje rekursywnie przekopiowane do innego obszaru w pamięci - najpierw kopiowany jest początkowy zestaw danych, potem wszystko co było przez niego wskazywane, itd. Na końcu zwalniamy początkową pamięć. W ten sposób „przez odsiew” usuwane zostają elementy, na które nic nie wskazuje. I w ten sposób oszczędza się na konieczności ustawiania bitów w "mark and sweep", dodatkowo, regularnie defragmentuje się pamięć. Problemy jakie mogą wystąpić to konieczność poniesienia kosztu kopiowania oraz konieczność posiadania dużej ilości wolnej pamięci. Ten sposób byłby bardziej praktyczny na systemach, na których możliwa jest tymczasowa alokacja dużej ilości pamięci. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

104 Programowanie i testowanie w Microsoft Mobile ASP.NET - przykłady
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

105 © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ
Tabela 1. Kontrolki dostępne w środowisku .NET Compact Framework © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

106 Przykład Tworzenia aplikacji, spełniającej funkcje klienta poczty elektronicznej (Outlook).
Co będzie potrzebne ? Visual Studio środowisko programistyczne, które jest także platformą do rozwijania aplikacji mobilnych wykorzystujących biblioteki i narzędzia Microsoftu. Niestety do naszych potrzeb jest wymagana wersja minimum Standard i nie wystarczy nam darmowa Express Edition. Windows Mobile 5.0 SDK - zestaw bibliotek i narzędzi do tworzenia aplikacji na urządzenia mobilne wyposażone w systemy operacyjne firmy Microsoft. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

107 dodanie na przestrzeni nazw pakietu „Outlook”
Pocket Outlook. Zawiera w sobie zarządzanie kontaktami, notatkami i zadaniami, jest to usługa, która działa „w tle”. Pełni ona tutaj rolę serwera danych, udostępniającego je na życzenie innych, korzystających z nich aplikacji. Jedną z nich będzie, ta, którą zaraz przygotujemy. using Microsoft.WindowsMobile.PocketOutlook; (1) public static OutlookSession outlook = new OutlookSession(); (2) foreach (Contact contact in outlook.Contacts.Items) (3) { lstAll.Items.Add(contact); } dodanie na przestrzeni nazw pakietu „Outlook” dodanie zmienną statyczną "outlook”. kod wypełniający naszą listę kontaktami otrzymanymi od Outlooka (umieszczony jest on w konstruktorze naszej aplikacji). lstAll - kontrolka listy (ListBox), znajduje się w zasobniku, w grupie Common Device Controls. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

108 (4) Metoda dodająca nowy kontakt.
Klasa OutlookSession jest głównym interfejsem do komunikacji z programem Pocket Outlook i pobierania wszystkich udostępnianych przez niego danych. Wystarczy zatem jeden obiekt tego typu, ale musi być on udostępniony dla wszystkich komponentów aplikacji. Dlatego też udostępniliśmy go jako publiczną zmienną statyczną w klasie, która reprezentuje główna formę aplikacji. Windows Mobile pozwala na przechowanie prawie czterdziestu różnych informacji o pojedynczej osobie – Jest to zadanie klasy Contact. if(!string.IsNullOrEmpty(textBox1.Text)) (4) { Contact newContact = new Contact(); newContact.FirstName = textBox1.Text; newContact.MobileTelephoneNumber = textBox2.Text; Form1.outlook.Contacts.Items.Add(newContact); Close(); } (4) Metoda dodająca nowy kontakt. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

109 (5) Metoda odczytująca zapisane kontakty.
private void ReadContacts() (5) { lstAll.Items.Clear(); foreach (Contact contact in outlook.Contacts.Items) lstAll.Items.Add(contact); } (5) Metoda odczytująca zapisane kontakty. Należy te operacje powtarzać po dodaniu każdego nowego rekordu, jeśli chcemy zobaczyć nowy rekord. Dzięki gotowej bibliotece Microsoft Telephony API nawiązanie polaczenia jest czynnością bardzo prostą. Przedstawiona aplikacja pokazuje zaledwie mały procent możliwości, jakie daje nam to środowisko. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

110 po czym wykonuje faktyczne połączenie
private void lstAll_SelectedIndexChanged(object sender, EventArgs e) (7) { if(lstAll.SelectedItem != null) Contact selected = (Contact)lstAll.SelectedItem; // ustanowienie połączenia Phone phone = new Phone(); phone.Talk(selected.MobileTelephoneNumber); } (7) Metoda nawiązująca połączenie. Uruchomiona zostanie, gdy wystąpi zdarzenie „SelectedValueChanged”. Środowisko stworzy szkielet metody do obsługi zdarzenia, a nam pozostanie wypełnić ją treścią. Funkcja najpierw sprawdza, czy element listy został zaznaczony (użytkownik mógł go również "odznaczyć"), potem zamienia element listy na obiekt typu Contact w celu wyłuskania z niego numeru telefonicznego, po czym wykonuje faktyczne połączenie Obiekt typu Phone pozwala na nawiązywanie połączeń. Można to zrobić wywołując jego metodę Talk() i podając jako parametr żądany numer telefonu. Warto zauważyć, że parametr ten jest literałem i można go podać w postaci alfanumerycznej, jak często podaje się numery telefonów w Stanach Zjednoczonych - na przykład MY-APPLE. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

111 (9) – Metoda wysyłająca sms.
using Microsoft.WindowsMobile.Telephony; (8) private void lstAll_SelectedIndexChanged(object sender, EventArgs e) (9) { if(lstAll.SelectedItem != null) Contact selected = (Contact)lstAll.SelectedItem; SmsMessage sms = new SmsMessage(selected.MobileTelephoneNumber, "Cześć!"); //wysłanie SMS-a outlook.SmsAccount.Send(sms); } (8) – potrzebne, aby móc nawiązywać połączenia telefoniczne. (9) – Metoda wysyłająca sms. Ponieważ rozmowy i wysyłanie krótkich wiadomości tekstowych SMS są funkcjami dostępnymi tylko w fizycznych urządzeniach i nie działają w emulatorze, to aby przetestować pełne działanie naszej aplikacji, trzeba użyć fizycznego urządzenia. Cała pozostała funkcjonalność może być jednak bez żadnych problemów testowana w emulatorze, jednak kiedy wywołamy funkcję połączenia, czy wysłania widomości, skończy się to błędem. Przykład pochodzi z : © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

112 Dalsze możliwości: Phone telefon = new Phone(); telefon.Talk("112");
telefon.Talk("112", true); using Microsoft.WindowsMobile.PocketOutlook; // Dodajemy nowe spotkanie I ustawiamy mu szczegóły Appointment spotkanie = new Appointment();   spotkanie.Subject = "Nowe spotkanie testowe"; // Ustawiamy temat naszego spotkania  // Ustawiamy początek spotkania na 21 luty 2006 o // 18:30 spotkanie.Start = new DateTime(2006, 02, 21, 18, 30, 00); spotkanie.Duration = new TimeSpan(01, 00, 00); // Długość trwania spotkania ustalamy na 1 godz. spotkanie.ReminderVibrate = true; // Jako przypomnienie ustawiamy wibrację using (OutlookSession sesja = new OutlookSession()) // Tworzymy sesję Outlooka i dodajemy nasze nowe spotkanie {    sesja.Appointments.Items.Add(spotkanie); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

113 using Microsoft.WindowsMobile.PocketOutlook;
Message wiadomosc = new Message(); //tworzymy nową wiadomość wiadomosc.To.Add(new //dodajemy adresata naszej wiadomości wiadomosc.Subject = "temat"; //ustawiamy temat wiadomości wiadomosc.BodyText = "Przykładowy z jakimś załącznikiem"; //wpisujemy treść wiadomości wiadomosc.Attachments.Add(new //dodajemy załącznik do naszego -a  using (OutlookSession sesja = new OutlookSession()) //wysyłamy wiadomość przy użyciu domyślnego konta pocztowego {    sesja. Accounts[0].Send(wiadomosc); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

114 Przykład wykorzystania Bluetooth
using InTheHand.Net.Bluetooth; using InTheHand.Net.Sockets; using InTheHand.Net.Ports; using InTheHand.Net; BluetoothClient BClient = new BluetoothClient(); BluetoothDeviceInfo[] DevicesInfo = BClient.DiscoverDevices(); StringBuilder Info = new StringBuilder(); ClassOfDevice Class; DeviceClass Device; ServiceClass Service; // uslugi, oddzielone przecinkiem foreach (BluetoothDeviceInfo device in DevicesInfo) {        Info.Append("Class of device: " + Class.ToString() + "\r\n");        Info.Append("Device: " + Device.ToString() + "\r\n");        Info.Append("Service: " + Service.ToString() + "\r\n"); } InTheHand – bibioteka dla platformy .NET, dostepna pod adresem: © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

115 private void ConnectBT(String Adres) { try { bluetoothClient
private void ConnectBT(String Adres)         {               try                 {                     bluetoothClient.Connect(new BluetoothEndPoint((BluetoothAddress)Adres);                 }                 catch (Exception ex)                 {                     MessageBox.Show(ex.Message);                 }         } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

116 Programowanie i testowanie w Adroid OS
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

117 Historia Historia Androida rozpoczyna się w lipcu 2005 roku, kiedy to Google zakupiło Android Inc., niewielką firmę z Kalifornii. Założyciele firmy, którzy zaczęli pracę w Google to m.in. Andy Rubin (współzałożyciel firmy Danger), Rich Miner (współzałożyciel Wildfire), Nick Sears (T-Mobile) i Chris White (jeden z pierwszych inżynierów w WebTV). Wtedy o Android Inc wiedziano tylko tyle, że produkuje oprogramowanie dla urządzeń mobilnych. Już w Google zespół pod kierownictwem Rubina stworzył system operacyjny dla urządzeń mobilnych, oparty na Linuksie, z myślą o wytwórcach sprzętu mobilnego i operatorach telefonii komórkowej. Google już wtedy dobrał sobie partnerów w świecie sprzętu komputerowego i oprogramowania oraz zasygnalizował operatorom komórkowym gotowość do współpracy. 5 listopada 2007 roku powstło Open Handset Alliance, konsorcjum w którego skład wchodzą Google, HTC, Intel, Motorola, Qualcomm, T-Mobile, Sprint Nextel oraz NVIDIA. Powstało z myślą o rozwoju otwartych standardów dla telefonii mobilnej. Wraz z ogłoszeniem powstania OHA zaprezentowano platformę Android. 12 listopada 2007 roku OHA opublikowało pierwszą wersją Android SDK, w którego skład wchodzą narzędzia programistyczne, debugger, biblioteki, emulator, dokumentacja, przykładowe projekty, tutoriale, FAQ i inne. Programiści muszą zainstalować Android SDK na komputerze kompatybilnym z x86 z systemem Windows XP lub Vista, Mac OS X (lub późniejszym), bądź Linux (testowane na Ubuntu Linux Dapper Drake). SDK wymaga także Java Development Kit, Apache Ant i Pythona 2.2 (bądź późniejszego). Eclipse 3.2 (bądź późniejsze) jest jedynym oficjalnie obsługiwanym IDE dzięki wtyczce Android Development Tools Plugin, ale programiści mogą także używać narzędzi konsolowych w celu tworzenia i debugowania aplikacji na Androida. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

118 Pierwszym telefonem wyposażonym w ten system operacyjny stał się HTC Dream, w Polsce sprzedawany pod marką Era G1 przez sieć Era od lutego 2009 roku. Kolejne telefony z Androidem to HTC Magic, (W Polsce sprzedawany od czerwca 2009), oraz Samsung I7500 Galaxy. W czerwcu 2009 HTC zaprezentowało telefon HTC Hero który został wyposażony w HTC Sense, autorski interfejs użytkownika, wdrożony do platformy Android przez producenta telefonu. W związku z warunkami licencji telefon z HTC Sense nie może posiadać znaczka "with Google" nadrukowanego na obudowie, gdyż HTC wprowadziło daleko idące zmiany w platformie Android. Architektura Systemu System Android oparty jest o system Linux, posiada jadro w wersji 2.6, dostarcza ono podstawowy system usług takich jak ochrona, zarządzanie pamięcią, zarządzanie procesem, obsługa sieci itp. Jądro również służy jako warstwa komunikacji między hardwar'em a softwar'em. Wyższa warstwa zawiera biblioteki systemowe zapewniające obsługę m. in. Bazy danych SQLlite Protokołu SSL Multimediów (MPEG4, H.264, MP3, AAC, AMR, JPG, PNG, gif) Grafiki 2D / 3D, grafika 3D oparta na OpenGL ES 1.0 (przyśpieszenie sprzętowe jako opcja) System C library Inne © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

119 Architektura Systemu Android Źródło: http://android.gsm.pl
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

120 Obsługa systemu plików FAT32 Obsługa TCP/IP (TCP, UDP, etc)
Linux Kernel Linux Kernel for ARM bezpieczeństwo, zarządzanie pamięcią, zarządzanie procesami, obsługa sieci i sterowniki. Wspiera architekturę ARM od wersji V5T Do obsługi androida wykorzystuje się szereg rozszerzeń: alarm, ashmem, binder, power management, low memory killer, kernel degugger, and logger. Obsługa systemu plików FAT32 Obsługa TCP/IP (TCP, UDP, etc) © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

121 Dalvik maszyna wirtualna zoptymalizowana dla urządzeń mobilnych
Cechy systemu: Platforma aplikacji umożliwiająca ponowne wykorzystanie i wymianę modułów Dalvik maszyna wirtualna zoptymalizowana dla urządzeń mobilnych Zintegrowana przeglądarka oparta na wolnym oprogramowaniu WebKit Zoptymalizowana grafika wykorzystująca grafikę 2D; grafika 3D oparta na OpenGL ES 1.0 (przyśpieszenie sprzętowe jako opcja) SQLite dla przechowywania danych Obsługa formatów multimedialnych audio, wideo, obraz (MPEG4, H.264, MP3, AAC, AMR, JPG, PNG, gif) Obsługa GSM Obsługa Bluetooth, EDGE, 3G, i WiFi, CDMA. Obsługa aparatu fotograficznego, GPS, kompas, and accelerometr Przyjazne środowisko programistyczne z możliwością emulacji urządzenia, narzędzie do usuwania usterek, ustawienia wydajności oraz wykorzystania pamięci, plugin dla środowiska Eclipse Wsparcie dla XML. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

122 Framework Aplikacji Programiści mają dostęp do tego samego API z jakich korzystają podstawowe aplikacje. Pod spodem działających aplikacji znajduje się szereg aplikacji, usług i podsystemów: Zestawi Widoków, które można używać do budowania aplikacji (listy, siatki, kontenery tekstowe, przyciski, wbudowana przeglądarka) "Content Providers", czyli system umożliwiający dostęp do danych innych aplikacji (np. Kontaktów), lub do ich współdzielenia. Menedżer Zasobów zapewniający dostęp do zasobów takich jak lokalizacje, grafika i pliki layoutów Menedżer Powiadomień pozwalający wyświetlać własne powiadomienia w pasku stanu Menedżer Aktywności zarządzający cyklem życia aplikacji i udostępniający standardową nawigację © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

123 Biblioteki Android zawiera zbiór bibliotek C/C++ używanych przez różne componenty systemu. Te funkcje są prezentowane dla programistów poprzez "Android application framework". Niektóre z głównych bibliotek są wymienione poniżej: - System C - pochodzaca z BSD implementacja standardowej biblioteki C (libc), przystosowana do urządzeń bazujących na Linuxie - Media Libraries- oparta na PacketVideo's OpenCORE; biblioteki wspierają odtwarzanie i nagrywanie wielu popularnych formatów audio i video tak jak i statycznych plików graficznych: MPEG4, H.264, MP3, AAC, AMR, JPG, PNG - Surface Manager- zarządza dostępem do podsystemu wyświetlania aby bezkolizyjnie tworzyć ramki grafiki 2D i 3D z wielu aplikacji - LibWebCore - nowoczesny silnik przeglądarki sieciowej, ktory zasila zarówno przeglądarkę Androida jak i wbudowaną przeglądarkę internetową - SGL - silnik grafiki 2D - 3D libraries - implementacja bazująca na OpenGl ES 1.0 API; biblioteka używa zarówno sprzetowej alceleracji 3D (tam gdzie to możliwe) jak i włączonego w nią wysoko zoptymalizowanego programowego rasterizera 3D - FreeType - renderowanie bitmap i grafiki vektorowej - SQLite - potężna i lekka relacyjna baza danych dostępna dla wszystkich aplikacji © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

124 Przykłady urządzeń z zainstalowanych systemem Android
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

125 Dalvik virtual machine
Językiem, w którym pisane są aplikacje na Androida jest Java. Zwykle pliki z kodem źródłowym napisanym w Javie kompilowane są do plików .class, zawierających instrukcje dla wirtualnej maszyny. Instrukcje te nazywa się bytecode ‘em Javy (Java Bytecode). W momencie uruchomienia aplikacji wirtualna maszyna (JVM) ładuje owe pliki do pamięci i uruchamia zawarty w nich kod. Android nie posiada JVM! Zamiast JVM, Google zdecydował się wyposażyć Androida w technologię Dalvik. Dlaczego powstał Dalvik? Java nie jest już nową technologią, także od dłuższego czasu znajduje zastosowanie w urządzeniach mobilnych, pozwoliło to znaleźć pewne (choć) nieliczne, słabe punkty JVM. Jednakże Sun nie zdecydował się na radykalne zmiany, zatem Google postanowił takowych dokonać. Tak właśnie powstał Dalvik – nowoczesna wirtualna maszyna, przystosowana specjalnie do urządzeń mobilnych, gdzie szczególną uwagę należy zwrócić na małe zasoby pamięci, energii i niewielką prędkość procesorów. Wśród narzędzi zawartych w SDK znajduje się kompilator. Kompilator ten nie tworzy jednak plików .class z bytecode’m Javy, lecz pliki .dex z bytecode’m Dalvik’a. Następnie skompilowane pliki, wraz ze strukturą katalogów i znajdującymi się w nich multimediami, zostają spakowane – zamiast do pliku .jar - do pliku .apk (Android Package). Tak przygotowana aplikacja uruchamiana jest przez wirtualną maszynę Dalvik’a. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

126 Podstawowe różnice pomiędzy JVM Javy i DVM.
Lepsza obsługa pamięci, Lepszy Garbage Collector, Większą wydajność. Aplikacje pobierają mniej energii. Bytecode Dalvik’a nie jest w 100% kompatybilny z bytecode’m Javy. Nie zadziałają więc na Adnroidzie bardziej wyrafinowane sztuczki programistyczne, korzystające z Class Loader’ów czy Java Reflection API. Powoduje to także problemy z uruchomieniem na Androidzie projektów korzystających np. z języków takich jak Groovy, JRuby czy Jython. Brak wsparcia dla niektórych klas znanych z J2ME, np. AWT czy Swing. Brak JIT (ang. just-in-time compilation) Niekompatybilność Darvick VM jest jednak pewną wadą – dlatego Google rozważa możliwość pewnego „upodobnienia” DVM do JVM, m. in.: wprowadzenie ClassLoader’ów takie jak w Javie, a także pełne wsparcie dla Reflection API. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

127 Programowanie aplikacji dla platformy Android
Co będzie potrzebne? Abyśmy mogli programować, musimy najpierw pobrać odpowiednie SDK ze strony Należy także spełnić stosowne wymagania systemowe – SDK zadziała na Windows XP lub Vista, MacOS X lub nowszy (tylko na platformie x86)), Linux, będziemy potrzebować także JDK w wersji 5 lub 6. Wskazane jest zainstalowanie również środowiska Eclipse, ze względu na prostotę zarządzania projektami, nad którymi będziemy pracować. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

128 Model aplikacji Pakiet android (.apk)
Plik zawierający kod i ewentualne zasoby aplikacji, Task Jest to ta cześć pakietu, która użytkownik uważa za aplikację Proces proces jadra, w którym uruchamiana jest aplikacja, zwykle cały kod .apk uruchamiany w jednym procesie, Watek w ramach procesu jeden lub więcej wątków. Android unika tworzenia własnych dodatkowych wątków, dopóki nie jest to konieczne © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

129 Cykl życia aplikacji Tworząc nową aktywność (Activity) wywoływana jest metoda onCreate(), a następnie onStart() i onResume(). Dziedzicząc po klasie Activity, nie jest konieczne implementowanie każdej z tych metod. Najczęściej nadpisuje się metodę onCreate(), zawierając w niej kod, który jest uruchamiany podczas uruchomienia aktywności. W chwili gdy użytkownik uruchomi nową aktywność czy wręcz aplikację, poprzednia jest wstrzymywana, co objawia się wywołaniem metod onPause() oraz onStop(). W przypadku gdy użytkownik powróci do ekranu, system wywołuje metodę onRestart(), a gdy aplikacja jest zamykana - onDestroy(). W przypadku tworzenia rozbudowanego systemu z dużą liczbą klas dziedziczących po Activity, należy mieć na uwadze cykl ich życia. W przeciwnym wypadku łatwo można pogubić się w całym procesie, co może skutkować np. niemożnością zamknięcia całej aplikacji przez użytkownika. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

130 Programowanie i testowanie w Android OS - przykłady
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

131 Adroid rozdziela tworzenie Gui od logiki programu
Adroid rozdziela tworzenie Gui od logiki programu. W klasie „MainActivity” zawarta jest logika programu, Natomiast w plikach „main.xml” i „strings.xml” znajdują się elementy GUI. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

132 Klasa „Activity” public class HelloAndroid extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); s etContentView(R.layout.main); } Do metody onCreate przekazywany jest stan Activity z poprzedniego uruchomienia. Na początku trzeba wywołać metodę onCreate klasy Activity po której dziedziczymy (super.onCreate – żeby pojawiło się czarne okienko, które będziemy mogli wypełnić). Podstawową “jednostką” w aplikacji jest Activity, czyli aktywność z którą użytkownik ma do czynienia, pojedyncza “strona” aplikacji. Aplikacja może mieć wiele Activity. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

133 Przykładowy plik „main.xml”
Android rozdziela funkcje „logiki” programu, od jego części wizualnej. Ta bowiem zapisana jest w dwóch plikach, w formacie XML-a – „main.xml” oraz „Strings.xml” main.xml opisuje wygląd pierwszej strony naszej aplikacji. LinearLayout to kontener na elementy, który automatycznie ustawia je obok siebie w ustalonej orientacji (android:orientation=”vertical”/”horizontal”), wypadałoby, żeby główny kontener zajmował całą dostępną przestrzeń ekranu, więc mamy android:layout_width=”fill_parent” android:layout_height=”fill_parent”. TextView to normalny element tekstowy (takij jak JLabel, albo normalny tekst w HTML) jako wartość parametru android:text podawana jest otwartym tekstem zawartość, która ma zostać wyświetlona. lub referencję do wartości podanej w pliku res/values/strings.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" </LinearLayout> Przykładowy plik „main.xml” <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Hello Android</string> <string name="hello">Hello World, HelloAndroid!>/string> </resources> Przykładowy plik „Strings.xml” © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

134 ?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_height="wrap_content" android:text=„Tytul Pola"/> </RelativeLayout> Przykład pliku „Main.xml” – GUI będzie zawierał tylko jedno pole tekstowe o id „label” © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

135 Definicja dwóch pól tekstowych, w których można zapisać dwie liczby
<EditText android:layout_width="fill_parent" android:layout_height="wrap_content" /EditText> Definicja dwóch pól tekstowych, w których można zapisać dwie liczby © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

136 Definicja dwóch przycisków typu Button.
android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginLeft="10dip" android:text=„Oblicz" /> android:text=„Wyjdz" /> Definicja dwóch przycisków typu Button. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

137 Definicja pola wyboru działania.
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text=„Wynik"/> </RelativeLayout> Definicja pola tekstowego, w którym umieszczony zostanie wynik działania. <RadioGroup android:layout_height="wrap_content" android:layout_width="fill_parent"> <TextView android:layout_height="wrap_content" android:layout_width="fill_parent"/> <RadioButton android:checked="false" <RadioButton android:checked="false" <RadioButton android:checked="false" <RadioButton android:checked="false" </RadioGroup> Definicja pola wyboru działania. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

138 package pl.przem.android.bac;
import android.app.Activity; import android.os.Bundle; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.TextView; public class CalculatorActivity extends Activity { private EditText L1= null ; private EditText L2 = null; private EditText wynik = null; private RadioGroup dzialanie = null; Private Button Oblicz = null; Private Button wyjdz = null private TextView result = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); L1 = (EditText) findViewById(R.id.Liczba1); L2 = (EditText) findViewById(R.id.Liczba1); wynik = (TextView) findViewById(R.id.wynik); oblicz = (Button) findViewById(R.id.ok); wyjdz evaluateBtn = (Button) findViewById(R.id.cancel); } © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

139 Oblicz.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View pV) { CalculatorActivity.this.Kalkulator(); } }; private void Kalkulator() { int liczba1 = Integer.valueOf(L1.getText().toString()); int liczba2 = Integer.valueOf(L2.getText().toString()); int wynik = 0; String dzial = dzialanie.getCheckedRadioButtonId().tostring(); if(dzial==„dodaj”) wynik = liczba1 + liczba2; else if(dzial==„odejmij”) wynik = liczba1 - liczba2; else if(dzial==„mnoz”) wynik = liczba1 * liczba2; else if(dzial==„dziel”) if(liczba <>0)wynik = liczba1 / liczba2; else wynik = 0; } wynik.setText(wynik+””); © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

140 Przykład ilustruje sposób odczytu danych z serwera www
private String urlGet(String urlString){ URLConnection urlConnection = null; URL url = null; String string = null; try { url = new URL(urlString); urlConnection = url.openConnection(); InputStream inputStream = urlConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader reader = new BufferedReader(inputStreamReader); StringBuffer stringBuffer = new StringBuffer(); while((string = reader.readLine()) != null){ stringBuffer.append(string + "\n"); } inputStream.close(); Przykład ilustruje sposób odczytu danych z serwera www © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

141 string = stringBuffer.toString();
} catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { } return string; © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

142 Przykład ilustruje sposób obsługi bazy danych (SQLlite)
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; private final String DB_NAME = "mojaBaza"; SQLiteDatabase baza = null; try{ baza = this.openOrCreateDatabase(DB_NAME, MODE_PRIVATE, null); baza.execSQL("CREATE TABLE IF NOT EXISTS Osoby (Imie VARCHAR, Nazwisko VARCHAR)"); baza.execSQL("INSERT INTO Osoby Values('Lech','Kaczynski');"); baza.execSQL("INSERT INTO Osoby Values('Donald','Tusk');"); baza.execSQL("INSERT INTO Osoby Values('Lech','Walesa');"); baza.close(); Przykład ilustruje sposób obsługi bazy danych (SQLlite) Przykład ilustruje sposób łączenia się z baza danych, tworzenie tabeli oraz wstawianie do niej danych. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

143 ArrayList<string> results = new ArrayList<string>();
Cursor cursor = baza.rawQuery("SELECT LastName FROM Osoby WHERE Imie like 'Lech'",null); if(cursor.moveToFirst()){ //Metoda zwraca FALSE jesli cursor jest pusty do{ String Imie = cursor.getString(cursor.getColumnIndex("LastName")); results.add(Imie); }while(cursor.moveToNext()); //Metoda zwraca FALSE wówczas gdy cursor przejdzie ostatni wpis } baza.execSQL("DELETE FROM Osoby"); baza.close(); Przykład ilustruje odczyt danych z bazy (przez wywołanie odpowiedniego zapytania), oraz zamknięcie bazy. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

144 Objective-C i Objective-C++
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

145 Historia Objective-C i Objective-C++
Historia rozwoju języków programowania od (1927 do 2007) Źródło : objective c tutorial Historia rodziny języków Objective C zaczyna się mniej więcej ok. roku 1972, jednak trudno tutaj podać Dokładna datę. Język objective-c powstał jako obiektowa alternatywa do języka C, jednocześnie bardzo silnie korzystając z Smalltalk-80. Objective-C++ jest językiem, która znajduje się pomiędzy Objective-C a C++. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

146 Cocoa to zorientowane obiektowo API, działające pod systemem Mac OS X firmy Apple. Jest to jedno z pięciu głównych API dostępnych dla tego systemu - oprócz Cocoa istnieje jeszcze Carbon, Toolbox (dla środowiska Classic), POSIX (do programowania środowiska BSD) i Java. Nie bierze się pod uwagę innych, jak Perl czy Python, ponieważ za ich pomocą nie tworzy się zazwyczaj w pełni integralnych aplikacji. Aplikacje tworzone w Cocoa są tworzone głównie przy użyciu narzędzi programistycznych dostarczonych przez firmę Apple. Są to Xcode i Interface Builder, używający języka Objective-C. Jezyk Objective-C “rozszeza” w pewnien spsob jezyk C, zatem elementy składniowe, o jakie rozszerzono w tym celu język C, używają dwóch symboli: [] (Istnieje wiecej rozszerzeń składni, ale tylko te wchodzą w jakiekolwiek interakcje ze składnią języka C). Nawiasy kwadratowe są używane do wywoływania metod, do definicji specyficznych dla języka Objective-C. Istnieją oprocz tego specjalnie dla Objective-C wprowadzone typy, istniejące już według reguł języka C, z których najważniejszym jest id. Typ ten jest uniwersalną "referencją do obiektu" (dokładnie to wskaźnikiem, z punktu widzenia języka C). W Objective-C obiektem jest tylko to, co jest dostarczone przez samo rozszezenie, jakim jest ten jezyk, elementy takie jak liczby całkowite, czy zmiennoprzecinkowe, są obsługiwane już zgodnie z językiem C. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

147 Podstawy Objective-C 2.0 Komentaże w kodzie wyglądają tak samo jak w przypadku języków C czy C++ /* */ lub // Tryb bool: BOOL (TRUE lub FALSE) C++ //Pilk Foo.h #ifndef __FOO_H__ #define __FOO_H__ class Foo { ... }; #endif //Plik Foo.cpp #include "Foo.h" Objective-C //Plik Foo.h @interface Foo : NSObject { ... } @end //Plik Foo.m #import "Foo.h" @implementation Foo © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

148 Porównanie sposobu Tworzenia klas w językach C++ i Objective-C
Klasy i obiekty C++ class klasa { double liczba; public: int funkcja1(int x); float funkcja2(int x, int y); }; int klasa::funkcja1(int x) {...} float klasa::funkcja2(int x, int y) {...} Objective-C @interface klasa : NSObject { double Liczba; } -(int) funkcja1:(int)x; -(float) funkcja2:(int)x :(int)y; @end @implementation klasa -(int) funkcja1:(int)x {...} -(float) funkcja2:(int)x :(int)y {...} Porównanie sposobu Tworzenia klas w językach C++ i Objective-C Znak “-”, że jest to metoda obiektu. Znak '+‘ oznaczalby, ze jest to metoda klasy (odpowiednik metody statycznej w C++). © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

149 public, private, protected
Objective-C definiuje klase- korzen (w Javie wystepuje podobny mechanizm, tam stanowi to klasa “Object”). Wszystkie wbudowane lub tworzone przez programiste klasy powinny być potomkiem klasy głównej. W Framworku Cocoa jest to NSObject. Smalltalk i Java korzystaja z tego mechnizmu, a zatem Objective-C rowniez, C++ natomiast nie. public, private, protected C++ class Klasa { public: int x; int Metoda_publiczna(); protected: int y; int Metoda_chroniona(); private: int z; int Metoda_prywatna(); }; Objective-C @interface Foo : NSObject { @public int x; @protected: int y; @private: int z; } -(int) Metoda_publiczna; -(int) Metoda_chroniona; -(int) Metoda_prywatna; //wszystkie są metodami publicznymi @end © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

150 pól (zmiennych), funkcje (metody) mogą być tylko publiczne.
W C++ istnieją trzy modyfikatory dostępu : publiczny, chroniony i prywatny, domyślnym jest ten ostatni. W Objective-C tez występują trzy wymienione atrybuty dostępności, jednak zastosowane mogą być tylko do pól (zmiennych), funkcje (metody) mogą być tylko publiczne. Można jednak utrudnić dostęp do metod, które w języku C++ miały być prywatne. Pewnym sposobem jest zaimplementowanie tych metod, ale bez umieszczania ich deklaracji w interfejsie. Nie utrudnia to bowiem ich późniejszego wywołania, lecz nie będą one widoczne dla osób, które nie wiedzą o ich istnieniu. Taka możliwość (implementacji metody bez jej wcześniejszej deklaracji jest cechą Objective-C ) Pola Statyczne. Pola statyczne jako takie w Objective-C nie występują, zastąpić je można za pomocą zmiennym globalnych. W kompilatorze GCC można też używać pól klasy (W POC już nie.), natomiast metody (funkcje) mogą być Metodami klasy, a nie obiektu (odpowiednik metod statycznych w C++). © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

151 Metody (funkcje) w klasach
Typy zwracane umieszczone są w nawiasach. Parametry rozdzielane są za pomocą dwukropka (:). Nazwa Metody może być taka sama jak nazwy atrybutów. C++ void Array::insertObject(void *anObject, unsigned int atIndex) shelf.insertObject(book, 2); Objective-C -(void) insertObject:(id)anObject:(unsigned int)index [shelf insertObject:book:2]; Objective-C, przykład 2 -(void) insertObject:(id)anObject:(unsigned int)index [shelf insertObject:book:2]; //Error ! [shelf insertObject:book atIndex:2]; //OK © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

152 (sending the message) z metody do obiektu.
Ważna Uwaga! W przypadku Objective-C nie wywołujemy metody na rzecz obiekty, a wysyłamy wiadomość (sending the message) z metody do obiektu. [odbiorca wiadomosc/polecenie]  Wysłać można wiadomośc nie tylko do obiektu z klasy, w której dana metoda istnieje, zawdzięczamy to mechanizmowi forwarding facility. Jeśli jednak wysłana zostanie wiadomość do metody, która nie istnieje To błąd pojawi się dopiero podczas wykonywania programu, a nie podczas kompilacji ! Istnieją dwa rodzaje celów w Objective-C : self i super. self – to odpowiednik konkretnego obiektu w C++ super – podobnie jak w Javie – odpowiednik klasy-rodzica. Dostęp do zmiennych wewnątrz metod (funkcji) W C++ odbywa się to za pomocą „this->”, a w Objective-C „self->” © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

153 C++ class Klasa { int x; int y; void funkcja(int x); }; void Klasa::funkcja(int x) This->x =x; } Objective-C @interface Klasa : NSObject { int x; int y; } -(void) funkcja:(int)x; @end @implementation Klasa -(void) funkcja:(int)x self->x =x; © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

154 Przeciążanie metod (funkcji) w Objective-C
W języku Objective-C nie można przeciążać funkcji (chyba, że dysponujemy kompilatorem obsługującym Standard C99, jak np. GCC). Jednak nawet wtedy wygląda to inaczej niż w języku C++. int f(int); int f(float); //Error : C functions cannot be overloaded -(int) g:(int) x; -(int) g:(float) x; //Error : this method is not different -(int) g:(int) x :(int) y; //OK : two anonymous labels -(int) g:(int) x :(float) y; //Error : not different from the -(int) g:(int) x andY:(int) y; //OK : second label is "andY" -(int) g:(int) x andY:(float) y; //Error : not different from the //previous one -(int) g:(int) x andAlsoY:(int) y; //OK : second label is //"andAlsoY", different from "andY" © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

155 Może delegować na tzn. asystenta.
Delegacja wiadomości do nieznanego obiektu (Delegating a message to an unknown object). W objective-C istnieje możliwość delegowania wiadomości do nieznanego obiektu, lub np. cześć zadania Może delegować na tzn. asystenta. W C++, jeśli chcemy wywołać metodę, to musi być ona wcześniej zaimplementowana, już w momencie kompilacji. Inaczej jest w języku Objective-C, tutaj można takie działanie wykonać. Jeśli, podczas działania Programu metoda nie będzie nadal zaimplementowana to wiadomość będzie zignorowana, może też Zostać zgłoszony odpowiedni wyjątek. Obsługa wyjątków Obsługa wyjątków w języku Objective-C jest podobna bardziej do Javy niż do C++. Jednym z powodów jest występowanie słowa kluczowego „Finally”. „Finally” jest oczywiście blokiem opcjonalnym. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

156 Przykład obsługi błędów w języku Objective-C
@try{ dangerousAction(); // Tutaj może wystąpić błąd } @catch (MyException* e){ doSomething(); //Akcja w przypadku wystąpienia wyjątku nr1 @catch (NSException* e){ doSomethingElse(); //Akcja w przypadku wystąpienia wyjątku nr2 @throw // Tutaj może wystąpić kolejny błąd. Rzucamy wyjątek. @finally{ cleanup(); Przykład obsługi błędów w języku Objective-C © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

157 Obsługa wątków w Objective-C
Generalnie obsługa wątków jest podobna jak w Javie, synchronizacja wątków odbywa się przy pomocy mechanizmu „Mutex”, ale słowo kluczowe dla tego bloku jest identyczne jak w Javie @ synchonized wymaga obiektu jako parametr (dowolny obiekt, na przykład własny) do stosowania jako blokady. @implementation MyClass -(void) criticalMethod:(id) anObject { @synchronized(self) } @synchronized(anObject) @end © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

158 Tworzenie obiektów w Objective-C, Przykład programu.
Obiekt w Objective-C stworzyć można po wywołaniu (ściślej mówiąc po wysłaniu wiadomości) na obiekcie klasy metody new: id object = [Klasa new]; Klasa *Obiekt; Obiekt = [Klasa alloc]; Klasa = [Klasa init];  Wszystkie obiekty podczas ich deklaracji muszą być poprzedzone gwiazdką "*", ponieważ są to wskaźniki (referencje) do tych obiektów. Każdy obiekt musi mieć przydzieloną pamięć - alloc oraz musi być zainicjowanym - init. Pamięć przydziela się poprzez wywołanie metody alloc z klasy, która jest dziedziczona po NSObject. Metoda alloc jest metodą klasy nie obiektu - o tym trochę później, który zwraca typ. Natomiast metoda init jest wywołana już dla naszego obiektu. Jest ona dziedziczona również poprzez NSObject. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

159 int main(int argc, char. argv[]) { kalkulator
int main(int argc, char *argv[]) {     kalkulator *przyklad = [[kalkulator alloc] init];     [przyklad setA: 25];  [przyklad setB: 30]; [przykład dodaj];         printf(„wynik %d \n", [kalkulator wynik]);                     [kalkulator release];     return 0; }  © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

160 Programowanie Iphone z wykorzystaniem języka Objective-C
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

161 Środowisko Pracy Niestety wymaganiem by rozpocząć przygodę z programowaniem na iPhone jest posiadanie komputera Mac z systemem operacyjnym Mac OS. Teoretycznie istnieje możliwość instalacji systemu Mac Os na komputerze PC, ale jest tu zadanie raz, że trudne (problemy ze sprzętem, sterownikami itp.), a dwa, ze niezgodne z prawem - System jest przeznaczony tylko dla komputerów ze stajni Apple. Jest to zapewne świadome działanie firmy Apple na rzecz rozpowszechniania ich systemy kosztem ilości osób zaangażowanych w tworzenie aplikacji na iPhone. Środowisko programistyczne XCode i Interface Builder Apple dostarcza w swoim centrum dla programistów paczkę SDK (obecnie – iPhone SDK for iPhone OS 2.1 ). Po pobraniu SDK dostajemy w pakiecie: XCode – środowisko programistyczne Interface Builder – środowisko do graficznego projektowania interfejsu Instruments – oprogramowanie do testowania aplikacji. interface simulator – symulator iPhone na Maca © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

162 Cały system, jaki znajduje się w telefonie…
Uruchamiając aplikację mamy cały system, jaki jest uruchomiany na urządzeniu, a więc jest do dyspozycji sprzęt taki jak kamery, żyroskop sprzętowy, czy wspomagania grafiki. Dostępne są także ustawienia telefonu czy też albumy zdjęć. Multitouch Użytkownicy iPhone dostali do dyspozycji ekran dotykowy z wykrywaniem wielu punktów dotykowych. Tym samym programiści muszą zwrócić uwagę by elementy, które można dotknąć są wystarczająco duże. Na szczęście standardowe elementy interfejsu podpowiadają swoją wielkością jakie są zalecenia ze strony Apple. Apple wspierał kiedyś także SDK dla Javy jednak zaprzestał na rzecz własnego języka. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

163 Objective-C raz jeszcze…
Klasy Klasy definiujemy w plikach o rozszerzeniu *.h natomiast implementacje klasy dokonujemy w plikach o rozszerzeniu *.m lub *.mm dla C++. W pliku *.h definiujemy zmienne oraz metody klasy. Poniżej składnia deklaracji klasy: @interface Klasa : NSObject { int x; int y; } -(void) funkcja:(int)x; @end @implementation Klasa -(void) funkcja:(int)x { self->x =x; } @end © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

164 (void)insertObject:(id)anObject atIndex:(NSUInteger)index
Powyżej deklaracja metody dla instancji obiektu ( + na początku deklaracji oznaczałby metodę statyczną). insertObject przyjmującej dwa parametry Pierwszyz nich : ((id)anObject) to wskaźnik. Natomiast drugi parametr - atIndex jest obiektem typu NSUInteger przypisany do zmiennej wewnętrznej index. Wysyłanie wiadomości NSMutableArray* myArray = nil; // tworzenie nowej modyfikowalnej tablicy myArray = [NSMutableArray arrayWithCapacity:0]; Wiadomość jest opisana pomiędzy nawiasami kwadratowymi []. Na początku wpisany zostaje odbiorca, a następnie parametry. Można wykorzystać wyniki wiadomości jako obiekty w parametrach lub odbiorcach wiadomości. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

165 Projekt aplikacji na Iphone – aplikacja typu „Hello world”
Aby móc przetestować aplikację w rzeczywistym środowisku pracy bez uczestnictwa w Developer Program należy zainstalować wersję firmware, pozbawioną zabezpieczeń. (można to wykonać na Windowsie lub Mac OS X), jednak stoi to w sprzeczności z prawem… Tworzenie nowego projektu W celu stworzenia naszej pierwszej aplikacji musimy uruchomić środowisko XCode oraz stworzyć nowy projekt wybierając z menu File -> New Project, z możliwych projektów wybierz iPhone -> View Based. Z głównego okna wybierz plik nazwa_aplikacji.xib i kliknij na nim dwukrotnie. Otworzy się Interface Builder, w którym można dowolnie zmieniać wygląd widoków, jakie umieszczone są w projekcie. Pliki *.xib opisują widoki, natomiast Interface Builder jest pomocny w szybkim edytowaniu podstawowego zachowania elementów interfejsu. By wypisać “Hello world” wystarczy umieścic jedynie odpowiedni Label. Do tego potrzebny będzie Object Inspector, którego wywołać można z menu Window w IB. W oknie aplikacji umieścimy podstawowy widok, by to uczynić przeciągnij z OI ikonkę View do okna aplikacji. Następnie dodać do niego trzeba element Label (przeciągnij go do wcześniej przeciągniętego widoku). Kliknij dwukrotnie na upuszczonym elemencie, a następnie wpisz “Hello World!“. Uruchomienie projektu Sprawdź czy aplikacja działa w symulatorze. Projekt można zbudować klikając ikonkę Build and Go albo użyj skrótu Cmd + Enter. Po zbudowaniu się projektu powinien uruchomić się symulator iPhona oraz nasza aplikacja. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

166 Aplikacja „Kalkulator”
#import int main(int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int retVal = UIApplicationMain(argc, argv, nil, nil); [pool release]; return retVal; } plik main.m Kolejnym plikiem, który generowany jest automatycznie, jest delegator aplikacji, w projekcie nazywa on się Base<nazwa_projektu>AppDelegate. Definicja klasy jest w pliku o rozszerzeniu .h a implementacja w pliku .m. Tak stworzony projekt można uruchomić kombinacją Cmd + B lub klikając Buil and Go. To co się pokaże to pusty ekran bez funkcjonalności. Ważne zasady: Aplikacja posiada tylko jedno okno. W programie tworzymy tylko widoki, które pokazujemy lub ukrywamy iPhone OS nie wspiera zarządzaniem poprzez garbage collection. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

167 File’s Owner – obiekt reprezentujący aplikację (UIApplication).
Tworzenie Widoku W celu stworzenia widoku, należy stworzyć plik o rozszerzeniu xib, służą one do projektowania interfejsu używając programu Interface Builder, dostarczanego wraz z SDK. Generowany jest automatycznie jeden plik tego typu, który opisuje główne okno, można je obejrzeć po uruchomieniu projektu w symulatorze. By edytować ten plik wystarczy dwa razy kliknąć na MainWindow.xib. Automatycznie generowane są: File’s Owner – obiekt reprezentujący aplikację (UIApplication). First Responder – obiekt przechwytujący zdarzenia multi-touch (pol. zdarzenia wielodotykowe). Base Calculator App Delegate – Obiekt odpowiedzialny za wyświetlenie okna i zainicjalizowanie widoku. Jest także odpowiedzialny za przywrócenie aplikacji do poprzedniego stanu, przechwytywanie ostrzeżeń o braku pamięci, odpowiadanie na zmiany orientacji urządzenia. Obiekt ten jest powiązany z klasą Delegatorem aplikacji. Window – obiekt reprezentujący okno, które widać w aplikacji. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

168 Interfejs użytkownika – wykorzystanie wbudowanych kontrolek
Tworzenie interfejsu użytkownika (GUI), w oparciu o wbudowane kontrolki Przypomina tworzenie GUI w innych środowiskach (np.. MS Visual Basic 6.0, czy C# / vb# w MS Visual Studio 2005/2008). Każda kontrolka posiada swoje właściwości, które można edytować zarówno Programowo, jak i korzystając z graficznego interfejsu środowiska Xcode. Rysunek po prawej przestawia wygląd okna właściwości dla kontrolki typu „TextField”. W przypadku aplikacji „Kalkulator” należy zatem dodać Przykładowo : dwa pola typu „TextField” – do wpisywania liczb, pole typu „TextField” lub „Label”, które będzie zwierało wynik działania, oraz kontrolka Typu „Button”, która spełniać będzie rolę przycisku. Zakładamy, ze nasz kalkulator jedynie dodanie do siebie dwie, wprowadzone Liczby i wyświetla wynik tej sumy. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

169 Kontroler Aplikacji Kontroler aplikacji odpowiedzialny jest m.in. za obsługę akcji wykonywanych przez użytkownika, nawigację oraz zarządzanie pamięcią. Każdy widok w aplikacji musi być połączony z takim kontrolerem, który będzie obsługiwał funkcjonalności. Klasą obsługująca widoki jest UIViewController. Dostarcza ona podstawowe funkcjonalności. W celu stworzenia kontrolera w XCode wybieramy File -> New File wybierając jako typ pliku UIViewController subclass. Następnie trzeba stworzyć zmienne dla elementów stworzonych w widoku. Pozwoli to na połączenie widoku z kontrolerem oraz na sterowanie widokiem. Tworzymy: BaseCalculatorViewController.h : #import @interface BaseCalculatorViewController : UIViewController { IBOutlet UITextField *firstNumber; //Słowo IBOutlet mówi kompilatorowi, że dana IBOutlet UITextField *secondNumber; //zmienna ma być widoczna dla Interface Buildera. IBOutlet UILabel *result; NSInteger fNumber, sNumber; } @property (nonatomic, retain) UITextField *firstNumber; //linijki kodu oznaczone jako @property (nonatomic, retain) UITextField *secondNumber; //definiują właściwości klasy @property (nonatomic, retain) UILabel *result; //Atrybut retain oznacza, że przy przypisywaniu obiekt jest zachowywany. @property (nonatomic) NSInteger fNumber; @property (nonatomic) NSInteger sNumber; -(IBAction)displayMessage:(id)sender; //ta metoda posłuży do obsługi zdarzenia(kliknięta klawisza) @end © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

170 Obsługa zdarzeń Tworzymy plik BaseCalculatorViewController.m : @implementation BaseCalculatorViewController @synthesize firstNumber, secondNumber, result, fNumber, sNumber; -(IBAction)displayMessage:(id)sender { self.fNumber = [firstNumber.text integerValue]; self.sNumber = [secondNumber.text integerValue]; NSString *tmpString = nil; if(self.fNumber == 0 || self.sNumber == 0) { tmpString = [[NSString alloc] some number"]; } else { tmpString = [[NSString alloc] %d", (self.fNumber + self.sNumber)]; } result.text = tmpString; [tmpString release]; W celach edukacyjnych została tu nadmiarowo stworzona zmienna tmpString. Pokazuje ona jak alokować (alloc), inicjalizować (initWithFormat) i uwalniać pamięć (release). Przy użyciu metody initWithFormat można tworzyć sformatowane ciągi znaków. jest podmieniany na parametr podany dalej. Można też używać innych znaków formatujących np. %s, %d występujące w funkcji printf z języka C. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

171 z pamięci. Zrobić to można następująco:
W stworzonym kontrolerze zawarte jest kilka właściwości o atrybucie retain, które powinniśmy uwolnić z pamięci. Zrobić to można następująco: (void)dealloc { [firstNumber release]; [secondNumber release]; [result release]; [super dealloc]; } Dodanie widoku do okna Kolejnym krokiem jest dodanie widoku jako podwidoku istniejącego okna. Utworzyć trzeba plik BaseCalculatorAppDelegate.h, a w nim zmienną typu BaseCalculatorViewController. Jest to typ nieznany kompilatorowi, dlatego też trzeba zadeklarować ten typ używając #import @class BaseCalculatorViewController; @interface BaseCalculatorAppDelegate : NSObject { IBOutlet UIWindow *window; BaseCalculatorViewController *viewController; } @property (nonatomic, retain) UIWindow *window; @property (nonatomic, retain) BaseCalculatorViewController *viewController; @end © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

172 W pliku implementującym (
W pliku implementującym (.m) W celu przypisania stworzonego widoku do okna wykorzystać trzeba metodę applicationDidFinishLaunching. Jest ona wywoływana jak tylko aplikacja zakończy proces uruchamiania się. Wykorzystać można ją do ustawiania pierwszego widoku i przywracania stanu aplikacji. #import "BaseCalculatorAppDelegate.h" #import "BaseCalculatorViewController.h" @implementation window, viewController; -(void)applicationDidFinishLaunching:(UIApplication *)application { //załadowanie widoku z bliku nib BaseCalculatorViewController *vController = [[BaseCalculatorViewController alloc] bundle:[NSBundle mainBundle]]; self.viewController = vController; //ustawienie widoku [vController release]; //uwolnienie zmiennej [window addSubview:[viewController view]]; //dodanie widoku do okna [window makeKeyAndVisible]; } //uwidocznienie widoku (void)dealloc { [viewController release]; [window release]; [super dealloc]; } @end © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

173 Połączenie elementów w widoku z obiektami w kontrolerze widoku
Pierwszym krokiem jest połączenie stworzonych obiektów z elementami widoku. Można to uczynić za pomocą Identity Inspector (opcja dostepna w Interface Buildera.). Obok zmiennej view jest puste kółko, co oznacza, że nie jest połączone. Połączenie tworzy się poprzez przeciągniecie na widok tego ‘kółka’ i puszczeniu klawisza. Zamalowane kółko będzie informowało o połączeniu. Podobnie sytuacja wygląda z reszta elementów : result, firstNumber, secondNumber – należy je połączyć z odpowiednimi elementami na widoku. Ostatnie połączenie to połączenie metody wyświetlającej wynik z akcją kliknięcia przycisku. W connection inspector wybrać należy metodę displayMessage i połączyć ją ze zdarzeniem: “Touch Up Inside”. Projekt jest gotowy, można go skompilować i uruchomić w Xcode. Aplikacja powinna już działać, ale pojawi się pewna niedogodność. Po wpisaniu liczb klawiatura nie będzie się chowała. By to naprawić trzeba dodać protokół do klasy kontrolera. Deklaracja interfejsu kontrolera widoku. @interface BaseCalculatorViewController : UIViewController <UITextFieldDelegate> © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

174 Kolejnym krokiem jest ustawienie kontrolera widoku jako odbiorcę zdarzeń pól tekstowych oraz zaimplementowanie metody obsługującej ukrywanie klawiatury: (void)viewDidLoad { firstNumber.delegate = self; secondNumber.delegate = self; } Metoda viewDidLoad ustanawia kontroler widoku jako obiekt odbierający zdarzenia pól tekstowych. (BOOL)textFieldShouldReturn:(UITextField *)theTextField { if(theTextField == firstNumber || theTextField == secondNumber) { [firstNumber resignFirstResponder]; [secondNumber resignFirstResponder]; return YES; } Metoda textFieldShouldReturn sprawdza jaki obiekt wywołał metodę, jeżeli te obiekty mogą powodować ukrycie klawiatury, wysłana zostaje wiadomość resignFirstResponder do obiektów oraz zwracany jest wartość logiczna ‘YES’. Pozostało jeszcze ustawienie delegacji dla pól tekstowych na File’s Owner (obiekt proxy dla naszego kontrollera). W Interface Builderze wybierać należy widok, a następnie dla każdego pola tekstowego z menu Connections Inspector przeciągnąć trzeba pole delegate na obiekt File’s Owner. Teraz można ostatecznie skompilować i uruchomić projekt. © 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ

175 W wykładzie wykorzystano tutorial, dostępny pod adresem :
© 2009 mgr inż. Łukasz Jopek Katedra Informatyki Stosowanej PŁ


Pobierz ppt "Wykład 1 Wprowadzenie © 2009 mgr inż. Łukasz Jopek Katedra."

Podobne prezentacje


Reklamy Google