Laboratorium SW
Ćwiczenie 3
Konfiguracja środowiska deweloperskiego Java ME.
Interfejs wysoko-poziomowy i RMS
1 Cele ćwiczenia
Celem ćwiczenia jest:
1. Przygotowanie środowiska do pisania programów w Java ME.
2. Opanowanie technik tworzenia aplikacji J2ME.
3. Poznanie mechanizmów tworzenia interfejsu wysokopoziomowego aplikacji J2ME.
4. Poznanie mechanizmów obsługi pamięci nieulotnej.
2 Środowiska tworzenia i testowania programów J2ME
Możliwe środowiska do pisania programów w Java ME są następujące:
Niezbędnym pakietem jest:
a.
Java Platform Micro Edition Software Development Kit 3.2 (Java ME SDK 3.2).
Platformę można pobrać ze strony:
http://www.oracle.com/technetwork/java/javame/javamobile/download/sdk/index.html
Platforma zawiera to co potrzebne do pisania programów, w tym środowisko
uruchomieniowe oraz symulatory telefonów komórkowych.
Uwaga: pakiet Netbeans (zależnie od wersji) może już zawierać Java ME SDK.
Ponadto wygodnie jest wykorzystać jedną z platform deweloperskich Eclipse lub Netbeans.
Mariusz Fraś
b.
Eclipse wer. 3.7.2 Indygo (lub nowszy), wraz z Mobile Tools for Java (MTJ).
Środowisko IDE można ściągnąć z witryny http://www.eclipse.org.
Instalacja i konfiguracja (dla Eclipse 3.7.2):
i.
Pakiet rozpakować w wybranym katalogu. Uwaga: zaleca się nie stosować polskich
liter w nazwach katalogów.
Instytut Informatyki
ii.
Doinstalować dodatek MTJ. MTJ najlepiej doinstalować z poziomu programu.
opcja: Help→ Install New Software. W oknie Available Software obok pola Work with klikamy przycisk Add i wprowadzamy adres URL z lokalizacją repozytorium Eclipse
Indigo: http://download.eclipse.org/releases/indigo. Zaznaczmy pakiety Mobile
Tools for... w węźle Mobile and Device Developement i zatwierdzamy instalację.
Politechnika Wrocławska
iii.
Zainstalować Java ME SDK Plug-in do Eclipse:
Ściągnąć ze witryny www.oracle.com Java ME SDK Plug-in do Eclipse (plik .zip).
Następnie z poziomu programu Eclipse wybieramy:
opcja: Help→ Install New Software. W oknie Available Software obok pola Work with klikamy przycisk Add, wybieramy Archive i wskazujemy plik .zip z plug-in’em.
Zatwierdzamy instalację.
1
Laboratorium SW
iv.
Zintegrowanie Eclipse z Java ME SDK (ustawienie emulatorów urządzeń):
- w menu Window wybieramy polecenie Preferences.
- drzewku rozwijamy Java ME i wybieramy Device Management,
- klikamy przycisk Manual Install,
- w oknie Import Devices, w polu Specify search directory wpisujemy ścieżkę katalogu
gdzie zainstalowano Java ME SDK (zostaną wyszukane emulatory urządzeń),
- wybieramy emulatory (najlepiej wszystkie) i zatwierdzamy.
Może być czasami pomocne (do przetestowania w danym środowisku) ustawienie:
- w oknie Window→ Preferences rozwijamy Java i w drzewku wybieramy Debug,
- usuwamy zaznaczenie opcji Suspend execution on uncaught exceptions i Suspend
execution on compilation errors oraz zmieniamy wartość pola
Debugger timeout (ms) na większą.
Konfiguracja środowiska Eclipse oraz tworzone projekty aplikacji zapamiętywane są
w katalogu .workspace. Usunięcie go spowoduje konieczność ponownej konfiguracji.
c.
Netbeans IDE wer. 7.2.1 (lub nowsza, lub nieco starsza).
Pakiet Netbeans zależnie od wersji może zawierać starszą wersję SDK. Szczegóły
instalacji dostępne są na stronach www.oracle.com i netbeans.org.
Uwaga 1: Wymieniony wyżej opis konfiguracji Eclipse dotyczy wersji 3.7.2. Inne wersje
Eclipse (w tym najnowsza) mogą wymagać innych zabiegów, które są opisywane na
stronach www.oracle.com lub różnych forach internetowych.
Uwaga 2: W przypadku instalacji Netbeans z Java ME SDK, a potem instalacji Eclipse, przy
konfiguracji Eclipse, należy szukać katalogu z Java ME SDK w podkatalogach Netbeans.
3 Architektura MIDleta
Mariusz Fraś
3.1
Cykl życia MIDleta
Cykl życia midleta (MIDleta) przedstawia poniższy schemat, na którym można wyróżnić 3
stany, w których może się on znajdować.
new()
Instytut Informatyki
destroyApp()
Zawieszony
(Paused)
Zakończonu
Politechnika Wrocławska
pauseApp()
startApp()
(Destroyed)
Aktywny
(Active)
destroyApp()
2
Laboratorium SW
Midlet musi zawierać 3 niezbędne metody do zarządzania jego stanem. Z cyklu życia
wynika, że metoda startApp() może być wykonywana wielokrotnie, natomiast
konstruowanie midletu poprzez new() wykonuje się tylko raz, przed tą metodą. To oznacza,
że działania, które należy zrobić tylko raz powinny być wykonane w konstruktorze. Jeśli z
pewnych powodów muszą być wykonane dopiero w metodzie startApp(), to należy
wprowadzić mechanizm, żeby nie były wykonywane wielokrotnie. Przejście w stan
zawieszenia oznacza często potrzebę zwolnienia zasobów (np. ekranu), zatrzymania
timerów itd. Przejście w ten stan może się odbyć w dwojaki sposób. Jedną sytuacją jest gdy
maszyna Javy zawiesi midlet z powodu np. przychodzącej rozmowy telefonicznej. Drugą jest
możliwość samodzielnego przejścia w stan zawieszenia. W tym przypadku należy wykonać
zwolnienie zasobów (np. poprzez wywołanie metody pauseApp()) a następnie wywołać
metodę notifyPaused(). Informuje ona maszynę Javy, że aplikacja jest przygotowana do
zawieszenia. Maszyna KVM w najbliższym czasie zawiesi midlet, ale już nie wywoła jego
metody pauseApp()!
Aby powrócić do stanu aktywnego sam midlet (lub inny midlet) może wywołać metodę
resumeRequest(). Oznacza to, że midlet jest gotowy do działania i tylko czeka na
przydział zasobów.
Przejście ze stanu zawieszonego do aktywnego dokonuje się zawsze poprzez wywołanie
przez KVM metody startApp(). Jak wcześniej wspomniano, oznacza to, że należy
uważać, aby w tej metodzie nie rezerwować ponownie zasobów, jeśli wcześniej nie zostały
one zwolnione w metodzie pauseApp().
Podobnie sprawa się ma z metodą destroyApp(). Jest ona wywoływana przez KVM, gdy
system chce zamknąć midlet. Gdy wartość parametru logicznego tej metody jest równa
true, midlet będzie bezwzględnie zamknięty. Jeśli jednak wartość ta wynosi false, to
midlet może stwierdzić, że nie jest gotowy do zamknięcia i poinformować o tym fakcie
Mariusz Fraś
poprzez rzucenie wyjątku MIDletStatChangeException. Midlet można samodzielnie
zamknąć poprzez wywołanie metody notifyDestroyed(). Jej działanie jest analogiczne
to metody notifyPaused(), stąd wszelkie zwolnienie zasobów należy wykonać wcześniej.
Wyjątek może rzucać również metoda startApp(). Jeśli będzie to wyjątek
MIDletStateChangeException, to aplikacja przejdzie w stan zawieszenia, jeśli jakiś inny
wyjątek, to aplikacja zostanie zawieszona poprzez wywołanie destroyApp().
Instytut Informatyki
3.2
Interfejs wysokiego poziomu midletu
Midlet korzysta z ekranu w celu wyprowadzania informacji oraz z klawiatury do
wprowadzania informacji. Dostęp do ekranu realizuje się poprzez klasę Display. Jej
statyczna metoda getDisplay(MIDlet m) zwraca obiekt klasy Display dla midletu m. W
Politechnika Wrocławska
czasie działania midletu jest to zawsze jeden i ten sam obiekt tej klasy (wzorzec Singleton).
Odpowiada on za zarządzanie urządzeniami ekranu i klawiatury.
Interfejs wysokiego poziomu w Javie ME jest podobny do interfejsu w wersjach Javy SE i EE,
ale jest mocno ograniczony. Midlet może zawierać wiele pojemników-okien, jednak tylko
jedno okno w danym momencie może być wyświetlane. Pojemniki-okna to obiekty
dziedziczące po klasie Displayable. Tylko jeden midlet ma w danym momencie dostęp do
3
Laboratorium SW
ekranu. Pojemniki pozwalają na umieszczenie w nich innych komponentów. Składniki zwykłe
(kontrolki) dziedziczą po klasie Item i mogą być wstawiane do pojemników. Pojemnik-okno
jest ustawiany jako aktywny/widoczny dla ekranu za pomocą metody setCurrent(….klasy
Display . W klasie tej możemy sprawdzić czy wyświetlacz jest kolorowy (metodą
isColor()) i ile ma kolorów (numColors()), włączyć wibrację (vibrate(…)) lub też
poświetlenie (flashBacklight(…)). Dostępne w Javie ME pojemniki dla interfejsu
wysokiego poziomu to Form (formatka), TextBox (okno tekstowe), Alert (okno z
komunikatem alarmowym), List (okno z listą opcji). Każda z wymienionych klas umożliwia
pobranie danych nt. rozmiarów pojemnika (getWidth(), getHeight()), ustawić/pobrać
tytuł (setTitle/getTitle), sprawdzić, czy jest wyświetlony (isShown()).
TextBox
Ten pojemnik pozwala na wpisywanie tekstu. W konstruktorze podaje się tytuł, początkowy
tekst, maksymalną długość tekstu oraz flagę informująca jakie znaki są dozwolone i jak
prezentować wpisywany tekst (np. dla hasła są to gwiazdki). Posiada metody do
pobranie/ustawienia wpisanego tekstu oraz do sterowania kursorem.
Alert
Okienko alarmowe z komunikatem. W konstruktorze podaje się tytuł, tekst komunikatu, obraz
oraz typ komunikatu. Poprzez metodę setTimer(…) podaje się na ile milisekund ma być
okienko pokazywane. Przy wstawianiu obiektu tej klasy do obiektu Display należy w
metodzie setCurrent(…) podać jako drugi parametr inny pojemnik, do którego nastąpi
przełączeniu po upływie podanego czasu.
List
Okno z listą opcji. W konstruktorze podajemy tytuł oraz czy jest to wybór pojedynczy czy
wielu. Ponieważ klasa ta implementuje interfejs Choice, posiada metody do wstawiania
Mariusz Fraś
kolejnych opcji metodą append(…) oraz sprawdzania i ustawiania aktualnego wyboru.
Form
Najbardziej rozbudowany pojemnik. Pozwala dodawać/usuwać kontrolki, obrazki poprzez
metody append(…), insert(…), set (…) i delete(…). Zapamiętuje listę kontrolek w
postaci listy, którą organizuje na ekranie z góry do dołu, a w linii od lewej do prawej.
Instytut Informatyki
Do formatki można dodawać różne elementy (obiekty klasy Item). Dodatkowo można
dodawać element typu String. Poniżej krótki przegląd podklas klasy Item:
• StringItem - napis
• TextField – pole edycji tekstowej
• DateField – pole edycji daty
Politechnika Wrocławska
• ImageItem – obraz (niezmienny)
• Image – obraz (zmienny)
• ChoiceGroup – grupa pól wyboru
• Gauge - suwak
• Spacer – odstęp między komponentami
• Ticker – przesuwający się tekst (nie zaleca się jego używania)
4
Laboratorium SW
3.3
System zarządzania rekordami (RMS)
Record Management System (RMS) jest uniwersalnym sposobem przechowywania danych
zapisywanych przez midlety. Podstawowym elementem zapisu/odczytu jest rekord, czyli
tablica bajtów. Rekordy tworzą zbiór rekordów, przechowywany w obiekcie klasy
RecordStore. Każdy rekord ma unikalny identyfikator (numer). Każdy zbiór ma przypisaną
nazwę oraz właściciela (midlet), jednak można określić uprawnienia dla innych midletów.
Jeden midlet może mieć dowolną liczbę zbiorów rekordów. Zbiór można otworzyć/utworzyć
za pomocą metod:
static RecordStore openRecordStore(String nazwa, boolean flaga)
static RecordStore openRecordStore(String nazwa, boolean flaga,
int dostep, boolean zapis)
Gdzie nazwa, to nazwa zbioru rekordów, natomiast flaga określa czy zbiór ma być
utworzony jeśli jeszcze nie istnieje
Operacje możliwe do wykonania na zbiorze to:
• int getNumRecords() – podaje liczbę rekordów w zbiorze
• int getSize() – podaje rozmiar w bajtach zbioru rekordów
• int getSizeAvailable()– podaje rozmiar w bajtach wolnego obszaru pamięci
dostępnego dla zbioru rekordów
• byte[] getRecord(int id) – zwraca rekord (tablicę bajtów) o podanym
identyfikatorze id
• void addRecord(byte[] bufor, int początek, int n) – dodanie nowego
rekordu na końcu zbioru
Mariusz Fraś
(rekord ma postać tablicy bajtów o indeksach od początek do początek+n-1)
• void setRecord(int id, byte[] bufor, int poczatek,int n) – zmiana
zawartości istniejącego rekordu o identyfikatorze id
• void deleteRecord(int id) – usunięcie ze zbioru rekordu o identyfikatorze id
• void deleteRecordStore(String nazwa) – usunięcie całego zbioru rekordów o
Instytut Informatyki
podanej nazwie (usuwany zbiór musi być zamknięty)
• closeRecodStore() – zamknięcie zbioru.
Istnieje również mechanizm obsługi zbioru za pomocą iteratora RecordEnumeration oraz
słuchaczy.
Używając obiektów klas ByteArrayOutputStream oraz DataOutputStream można
Politechnika Wrocławska
łatwo wstawiać do strumienia dane różnych typów a następnie pobrać ze strumienia dane
postaci bajtów i zapisać do zbioru. Analogiczne można wczytywać dane różnych typów z
rekordu.
5
Laboratorium SW
4 Zadanie
Napisać aplikację, która będzie pozwalała wprowadzać, zapamiętywać i przeglądać
indywidualnie wymyślony zestaw danych. Aplikacja powinna się charakteryzować poniżej
podanymi szczegółowymi cechami.
1. Jako pierwszy ekran zrealizować główne menu aplikacji z opcjami wyboru:
a. wprowadzania danych,
b. przeglądania wprowadzonych danych,
c. zakończenia działania aplikacji.
itp. (to co będzie potrzebne)
2. Zrealizować wprowadzanie danych poprzez pojemnik Form i umieszczone w nim
kontrolki. Po wprowadzeniu danych wyświetlić informację o fakcie w oknie klasy Alert (a
w nim np. jakiś element identyfikujący dane (np. nazwisko jeśli są to dane osobowe, albo
model samochodu/samolotu/itp. w innym przypadku)).
Zestaw danych do wprowadzenia należy wymyślić samemu. Powinien on być na tyle
urozmaicony, żeby można było wykorzystać różne kontrolki.
3. Uzupełnić funkcję wprowadzania danych o zapis do pamięci trwałej wykorzystując
mechanizm RMS. Dostęp do danych powinien być tak zorganizowany, żeby w razie
potrzeby utworzyć odpowiedni zbiór i móc z niego korzystać po powtórnym uruchomieniu
aplikacji.
Uwaga: dla emulatora jest odpowiednia opcja dla restartu aplikacji. Wyłączenie
emulatora wymazuje wszystko.
4. Zaimplementować przeglądanie listy danych i po wyborze konkretnej pozycji
wyświetlenie pełnej informacji w oknie tekstowym.
5. Dodać opcję przeglądania ze względu na różne kryteria sortowania rekordów i/lub
Mariusz Fraś
filtrowania danych (rekordów).
6. Dodać funkcję kasowania danych (pojedynczych rekordów). Dodać przy tym możliwość
określenia, które dane kasujemy.
Uwaga: w przypadku kasowania danych przeglądanie danych musi to uwzględniać.
7. Dodać funkcję modyfikacji rekordu danych (jako oddzielną pozycję menu lub komendę
Instytut Informatyki
przy przeglądaniu danych). Przy modyfikacji danych dodać komendy zatwierdzania i
zaniechania edycji.
8. W ćwiczeniu należy wykorzystać jak najwięcej różnych elementów interfejsu wysokiego
poziomu. (przyciski, listy, różne pola wyboru, linie i pola tekstowe, pola daty i czasu,
suwaki, obrazki, itd. itp. ), a także możliwość formatowania kontrolek.
Politechnika Wrocławska
Ważne: różnorodność użytych środków będzie w ćwiczeniu oceniana.
9. Elementy aplikacji powinny być proporcjonalnie rozłożone, gdy uruchomimy aplikację na
różnych komórkach. W miarę możliwości uwzględnić orientację ekranu (pion/poziom).
10. Oddzielne logicznie elementy aplikacji należy umieszczać w osobnych klasach. Aplikacja
powinna mieć czytelną strukturę.
6