Darmowy fragment publikacji:
J2ME. Praktyczne
projekty. Wydanie II
Autor: Krzysztof Rychlicki-Kicior
ISBN: 978-83-246-2835-3
Format: 158×235, stron: 272
Naucz się efektywnie wykorzystywać możliwości oferowane przez J2ME!
• Zainstaluj najnowszą wersję środowiska Java ME SDK
• Poznaj zasady tworzenia aplikacji mobilnych
• Rozwiń swoje umiejętności w oparciu o praktyczne projekty z wykorzystaniem J2ME
J2ME, czyli Java 2 Micro Edition, to uproszczona wersja platformy Java, opracowana przez firmę Sun
Microsystems specjalnie dla potrzeb programowania urządzeń przenośnych, takich jak telefony
komórkowe czy palmtopy. Umożliwia tworzenie ciekawych i wydajnych aplikacji mobilnych, które
bez większych problemów można uruchamiać na sprzęcie o stosunkowo słabych parametrach
technicznych. Pozwala to osobom zainteresowanym produkcją gier, programów multimedialnych
czy narzędzi sieciowych swobodnie rozwinąć skrzydła w tej dziedzinie.
„J2ME. Praktyczne projekty. Wydanie II” to przydatny przewodnik po zaawansowanych
zagadnieniach, związanych z tworzeniem różnego rodzaju aplikacji mobilnych przy użyciu
środowiska Java. Autor pokrótce przedstawia w nim podstawowe informacje na temat
projektowania i kodowania programów działających na urządzeniach przenośnych, aby szybko
przejść do konkretnych przykładów zastosowania zdobytej wiedzy. Dzięki nim nauczysz się
tworzyć gry, aplikacje komunikacyjne, programy multimedialne i narzędzia GPS. Jeśli chcesz
szybko opanować J2ME, tej książki nie może zabraknąć na Twojej półce!
• Instalacja środowiska programisty J2ME
• Podstawowe informacje o platformie i sposobach jej używania
• Obsługa zaawansowanych wyświetlaczy
• Tworzenie aplikacji sieciowych i komunikacyjnych
• Przetwarzanie i wykorzystywanie danych XML
• Tworzenie aplikacji multimedialnych i obsługa kamer
• Projektowanie i programowanie gier
• Tworzenie aplikacji GPS
Dołącz do elitarnego grona programistów aplikacji mobilnych!
Idź do
• Spis treści
• Przykładowy rozdział
Katalog książek
• Katalog online
• Zamów drukowany
katalog
Twój koszyk
• Dodaj do koszyka
Cennik i informacje
• Zamów informacje
o nowościach
• Zamów cennik
Czytelnia
• Fragmenty książek
online
Kontakt
Helion SA
ul. Kościuszki 1c
44-100 Gliwice
tel. 32 230 98 63
e-mail: helion@helion.pl
© Helion 1991–2011
Spis treĈci
Wstöp .............................................................................................. 7
Rozdziaä 1. Warsztat dla MIDletów ..................................................................... 9
Instalacja oprogramowania ............................................................................................... 9
Tworzenie nowego projektu ........................................................................................... 10
Publikowanie MIDletu ............................................................................................. 11
Kod MIDletu .................................................................................................................. 12
Interfejs uĪytkownika ..................................................................................................... 14
MID Profile a kompatybilnoĞü MIDletu ................................................................... 14
Polecenia .................................................................................................................. 15
Podstawowe komponenty graficzne ......................................................................... 16
Przykáadowy projekt ....................................................................................................... 19
Rozdziaä 2. Podstawy aplikacji mobilnych ......................................................... 23
Przegląd klas wyĞwietlaczy ............................................................................................ 23
Canvas ...................................................................................................................... 23
Alert ......................................................................................................................... 26
List ........................................................................................................................... 26
Projekt — program graficzny ......................................................................................... 27
Rozdziaä 3. Zaawansowane rodzaje wyĈwietlaczy .............................................. 35
Obsáuga RMS w Javie .................................................................................................... 35
Zapis w RMS .................................................................................................................. 37
Tablice bajtów a odczyt danych ...................................................................................... 38
Usuwanie a zbiory .......................................................................................................... 39
Zaawansowane techniki przeglądania zbiorów ............................................................... 39
Projekt — program Notatki ............................................................................................ 40
Interfejs programu .................................................................................................... 41
Pakiet pl.helion.j2mepp.notatki ................................................................................ 41
WyĞwietlenie listy notatek ....................................................................................... 43
Obsáuga poleceĔ ....................................................................................................... 44
Przechowywanie danych i nie tylko ......................................................................... 45
Zarządzanie notatkami ............................................................................................. 49
Testowanie aplikacji ....................................................................................................... 52
Internet w MIDletach ..................................................................... 53
Projekt — czat na komórkĊ ............................................................................................ 53
Sieü — z czym to siĊ je? .......................................................................................... 54
Jak zawsze — interfejs ............................................................................................. 54
Rozdziaä 4.
4
J2ME. Praktyczne projekty
Obsáuga aplikacji ...................................................................................................... 56
Czas na internet! ....................................................................................................... 58
Obsáuga poáączenia w aplikacji ................................................................................ 61
Serwer czata ............................................................................................................. 66
Wysyáanie wiadomoĞci ............................................................................................. 70
Obsáuga poáączeĔ klienckich .................................................................................... 71
Podsumowanie projektu ................................................................................................. 76
Rozdziaä 5. Obsäuga XML w J2ME ..................................................................... 77
Projekt — czytnik RSS ................................................................................................... 77
J2ME a XML ............................................................................................................ 78
Wykorzystanie biblioteki kXML w MIDletach ........................................................ 79
Dziaáanie programu i jego interfejs .......................................................................... 79
JĊzyk RSS ................................................................................................................ 82
Struktura Dane ......................................................................................................... 84
Obsáuga poleceĔ w MIDlecie ................................................................................... 86
Pobieranie dokumentu RSS ...................................................................................... 88
PiĊkne jak gra na SAXofonie — biblioteka kXML pod lupą ................................... 89
Parser w praktyce ..................................................................................................... 91
Podsumowanie ................................................................................................................ 97
Rozdziaä 6. Multimedia w Twoim telefonie ........................................................ 99
Projekt — odtwarzacz multimedialny ............................................................................ 99
Obsáuga multimediów w telefonach ....................................................................... 100
Proces odtwarzania pliku ........................................................................................ 100
ħródáa plików multimedialnych ............................................................................. 101
Interfejs programu .................................................................................................. 102
Odtwarzacz a FileConnection Optional Package .................................................... 108
Implementacja przeglądarki systemu plików w projekcie ...................................... 111
Obsáuga multimediów w odtwarzaczu .................................................................... 115
Nagrywanie dĨwiĊku .............................................................................................. 119
Odtwarzanie nagrania ............................................................................................. 121
Obsáuga aparatu ...................................................................................................... 122
Przerywanie odtwarzania i zamykanie odtwarzacza ............................................... 123
Wykorzystanie RMS w projekcie ........................................................................... 125
Podsumowanie ....................................................................................................... 129
Rozdziaä 7. Zagrajmy! .................................................................................... 131
Projekt — gra „platformówka” ..................................................................................... 131
Struktura klas ......................................................................................................... 131
Game API ............................................................................................................... 132
Maáy MIDlet ........................................................................................................... 134
Páócienna gra .......................................................................................................... 134
Warstwy i duszki .................................................................................................... 137
Gáówna pĊtla gry .................................................................................................... 139
Wykorzystanie zalet páótna .................................................................................... 140
Duszki w grze ......................................................................................................... 144
Bohater w akcji ...................................................................................................... 150
Od bohatera do potworka ....................................................................................... 154
Globalna obsáuga potworków ................................................................................. 158
Strzelanie ................................................................................................................ 160
Zarządzanie pociskami ........................................................................................... 162
Dane a logika .......................................................................................................... 165
Grafika w grze ........................................................................................................ 170
Podsumowanie .............................................................................................................. 171
Spis treĈci
5
Rozdziaä 8.
J2ME a Bluetooth ........................................................................ 173
Projekt — usáuga szyfrująca ......................................................................................... 173
MIDlet .................................................................................................................... 174
Zasady dziaáania ..................................................................................................... 176
Znalazáem, wysáaáem, odebraáem! .......................................................................... 183
Kod klienta ............................................................................................................. 185
Podsumowanie .............................................................................................................. 190
Rozdziaä 9. Maäy szpieg — zdalna kamera ...................................................... 191
ZaáoĪenia projektowe ................................................................................................... 192
Nadawca ................................................................................................................. 192
Odbiorca ................................................................................................................. 193
Serwer .................................................................................................................... 194
Konfigurujemy serwer .................................................................................................. 194
Widok — interfejs aplikacji klienckiej ................................................................... 196
Kontroler — obsáuga zdarzeĔ i sterowanie aplikacją ............................................. 200
Timer i zadania ....................................................................................................... 202
Danie gáówne — HTTP bez trzymanki .................................................................. 205
Serwer w akcji .............................................................................................................. 210
SID — klucz jedyny w swoim rodzaju ................................................................... 213
Serwer i jego metody .............................................................................................. 216
Podsumowanie .............................................................................................................. 217
Rozdziaä 10. Lokalizator ................................................................................... 219
Wprowadzenie .............................................................................................................. 219
FunkcjonalnoĞü projektu ........................................................................................ 219
Interfejs uĪytkownika ................................................................................................... 220
Zaglądamy pod maskĊ… ........................................................................................ 229
Instalacja i konfiguracja bazy danych ..................................................................... 234
Przenosiny na serwer .............................................................................................. 235
MenedĪer bezpieczeĔstwa ...................................................................................... 242
Obsáuga bazy danych w aplikacji serwerowej ........................................................ 244
Spajanie w caáoĞü ................................................................................................... 247
Podsumowanie .............................................................................................................. 249
Dodatek A ................................................................................... 251
Projekt — edytor plansz ............................................................................................... 251
Podsumowanie .............................................................................................................. 254
Skorowidz .................................................................................... 255
Rozdziaä 6.
Multimedia
w Twoim telefonie
Telefony komórkowe coraz czĊĞciej zawierają dodatkowe udogodnienia, dziĊki którym
przestają byü tylko urządzeniami do prowadzenia rozmów. Jednym z najpopularniej-
szych sposobów przyciągania uwagi klientów jest dodawanie moĪliwoĞci multimedial-
nych, takich jak:
odtwarzanie plików dĨwiĊkowych (midi/wav/mp3),
odtwarzanie plików wideo (mpeg),
nagrywanie audio,
wykonywanie zdjĊü,
nagrywanie plików wideo.
J2ME umoĪliwia programistom wykorzystanie tych moĪliwoĞci, o ile dany telefon obsáu-
guje sprzĊtowo daną funkcjĊ.
Projekt — odtwarzacz multimedialny
Jak sama nazwa wskazuje, w niniejszym projekcie zostaną zaprezentowane wybrane
moĪliwoĞci multimedialne, które oferuje J2ME. Równie waĪną cechą programu bĊdzie
obsáuga wielu rodzajów Ĩródeá danych — odtwarzacz bĊdzie mógá wczytywaü dane
z internetu (za pomocą protokoáu HTTP), z lokalnego systemu plików (za pomocą
klas z pakietu javax.microedition.io.file) oraz z RMS. Oprócz odtwarzania zasobów
multimedialnych program umoĪliwi nagranie dĨwiĊku i zrobienie zdjĊcia — z moĪli-
woĞcią zapisu w RMS.
Na początku warto dowiedzieü siĊ, gdzie są zadeklarowane klasy obsáugujące multimedia
i jakie warunki musi speániaü urządzenie, aby dany rodzaj multimediów odtworzyü.
100
J2ME. Praktyczne projekty
Obsäuga multimediów w telefonach
Najbardziej funkcjonalnym API (w momencie pisania tej ksiąĪki — caáy czas są two-
rzone jego kolejne wersje) jest Mobile Media API 1.1, zdefiniowane w JSR-135. Zawiera
ono klasy i interfejsy przeznaczone do wykonywania wszystkich wspomnianych na
początku rozdziaáu czynnoĞci. Jak to zwykle bywa, API to nie jest powszechnie dos-
tĊpne w telefonach komórkowych. Dlatego najbardziej podstawowe elementy zawarte
w MMAPI zostaáy wydzielone i weszáy w skáad MIDP 2.0. Owa czĊĞü nosi nazwĊ
MIDP 2.0 Media API i jedynym warunkiem, który musi speániaü telefon, aby moĪliwe
byáa jego wykorzystanie, jest dostĊpnoĞü MIDP w wersji 2.0.
Za obsáugĊ multimediów odpowiadają pakiety javax.microedition.media, javax.
´microedition.media.control oraz javax.microedition.media.protocol. ZawartoĞü
tych pakietów moĪna podzieliü na trzy czĊĞci:
elementy dostĊpu do danych — na podstawie URL udostĊpniają strumienie
danych;
odtwarzacze — kontrolują proces przygotowania i odtwarzania (a takĪe
nagrywania) danych multimedialnych;
kontrolki — odpowiadają za konkretną wáaĞciwoĞü odtwarzacza, np. gáoĞnoĞü
lub wysokoĞü dĨwiĊku.
RóĔnice miödzy MMAPI a MIDP Media API
Jak wspomniaáem, MIDP Media API jest podzbiorem MMAPI. PoniĪsze zestawienie
zawiera zbiór wszystkich elementów dostĊpnych w MIDP Media API:
klasy: Manager;
klasy wyjątków: MediaException;
interfejsy: Control, Controllable, Player, PlayerListener, ToneControl,
VolumeControl.
MMAPI zawiera wszystkie powyĪsze elementy oraz szereg innych. Spora czĊĞü z nich
zostanie wykorzystana w projekcie.
Proces odtwarzania plikulnych
W niniejszym podrozdziale opiszĊ wszystkie czynnoĞci, które trzeba wykonaü, aby
odtworzyü plik multimedialny. Program zazwyczaj dysponuje adresem internetowym lub
ĞcieĪką dostĊpu do pliku. Na początek naleĪy wiĊc zapoznaü siĊ z metodą createPlayer()
klasy Manager. Tworzy ona obiekt odtwarzacza (klasy Player) na podstawie podanego
adresu lub strumienia:
Player odtwarzacz = Manager.createPlayer( http://serwer.org/plik.wav );
Rozdziaä 6. i Multimedia w Twoim telefonie
101
Dysponując gotowym obiektem odtwarzacza, naleĪy wspomnieü o stanach, w jakich
moĪe siĊ on znajdowaü. Są one okreĞlone nastĊpującymi staáymi (w kolejnoĞci od stanu
początkowego do odtwarzania):
UNREALIZED — odtwarzacz jest tuĪ po utworzeniu. Nie moĪna wykonaü
wiĊkszoĞci jego metod.
REALIZED — odtwarzacz ma informacje potrzebne do pobrania danych.
PREFETCHED — odtwarzacz dysponuje pobranymi danymi; jest gotowy
do rozpoczĊcia odtwarzania.
STARTED — odtwarzacz jest w trakcie odtwarzania pliku multimedialnego.
W przypadku przerwania odtwarzania przechodzi z powrotem do stanu
PREFETCHED.
CLOSED — odtwarzacz koĔczy dziaáanie i zwalnia zaalokowane zasoby.
Aby przejĞü do danego stanu, naleĪy wywoáaü metody: realize(), prefetch(), start(),
close(). Metoda stop() przerywa dziaáanie odtwarzacza i powoduje przejĞcie do stanu
PREFETCHED.
javax.microedition.media.Manager
public Player createPlayer(String url) — tworzy obiekt odtwarzacza
na podstawie adresu danego zasobu.
public Player createPlayer(InputStream is, String typ) — tworzy obiekt
odtwarzacza na podstawie danego strumienia wejĞcia i okreĞlonego typu MIME.
đródäa plików multimedialnych
MMAPI 1.1 daje olbrzymie moĪliwoĞci co do wyboru Ĩródeá, z których moĪna pobieraü
dane multimedialne. NajwaĪniejszą rolĊ odgrywa URL, przekazywany w parametrze
metody createPlayer(). Adres, jak kaĪdy inny, skáada siĊ z trzech czĊĞci. Jednak w przy-
padku lokalizatorów multimediów moĪe on przyjąü postaü daleko inną od tej znanej
z codziennego uĪytkowania komputera.
Podstawowym typem jest odtwarzanie plików pobranych za pomocą protokoáu HTTP.
URL przyjmuje wtedy postaü:
http://www.serwer.org/folder/plik.wav
gdzie http:// to okreĞlenie protokoáu, www.serwer.org — nazwa hosta (komputera,
z którym program musi siĊ poáączyü), a /folder/plik.wav — ĞcieĪka do pliku na
serwerze. Ta postaü jest znana; zupeánie inaczej wygląda jednak konstruowanie adresów
w przypadku przechwytywania danych audio i wideo.
Aby utworzyü obiekt klasy Player, który umoĪliwi rejestrowanie jakichkolwiek danych,
naleĪy zastosowaü protokóá capture://. NastĊpnie naleĪy podaü rodzaj przechwyty-
wanego materiaáu — audio lub video. Na tym nie koniec — po znaku zapytania moĪna
okreĞliü jego parametry techniczne, np. rate (czĊstotliwoĞü próbkowania w przypadku
dĨwiĊku) lub width i height (rozmiary obrazu w przypadku wideo).
102
J2ME. Praktyczne projekty
OczywiĞcie przechwytywanie materiaáu audio i wideo wymaga zastosowania dodatko-
wych kontrolek; są to odpowiednio: RecordControl i VideoControl. OmówiĊ je w jed-
nym z nastĊpnych podrozdziaáów, w momencie gdy zostaną zastosowane w naszym
projekcie.
Interfejs programu
Aby zrozumieü, dlaczego stosujemy taki, a nie inny sposób tworzenia interfejsu, trzeba
najpierw omówiü dziaáanie programu. Po uruchomieniu programu uĪytkownik musi
wybraü rodzaj Ĩródáa danych: internet, system plików lub RMS. Pozostaáe dwie moĪli-
woĞci to przechwytywanie — audio lub wideo. W przypadku pobierania pliku z internetu
sytuacja jest najprostsza — naleĪy udostĊpniü uĪytkownikowi pole do wprowadzenia
adresu. Zdecydowanie bardziej skomplikowane jest wykorzystanie systemu plików.
Nasz MIDlet udostĊpnia bowiem minimenadĪer plików, który umoĪliwia swobodne
poruszanie siĊ po strukturze katalogów. W przypadku zbioru rekordów program wyĞwie-
tla listĊ wszystkich zarejestrowanych multimediów. Bez wzglĊdu na sposób pobierania
uĪytkownik dociera do formatki, która jest wyĞwietlana przy odtwarzaniu plików.
OdtwarzaczMIDlet.java
private Odtwarzacz odtwarzacz;
private MenadzerPlikow menadzer;
private List menu;
private List listaFile;
private List listaRms;
private Form formaHttp;
private Form formaAparat;
private Form formaOdtwarzacz;
private List listaPrzechwytujaca;
private Display ekran;
private TextField poleUrl;
private final String[] POLECENIA_PRZECHWYTYWANIA = new String[]
{ Start , Stop , Odtworz , Zapisz };
private final String[] OPCJE = new String[]
{ Odtworz plik z Internetu , Odtworz plik z urzadzenia , Odtworz plik z
´RMS , Przechwyc audio , Zrob zdjecie };
}
Lista zmiennych ujawnia czĊĞciowo zawartoĞü projektu. Na początku są zadeklarowane
dwa kluczowe obiekty: odtwarzacz i menadzer. Pierwszy z nich odpowiada za wszelkie
kwestie związane z wykorzystaniem skáadników pakietu javax.microedition.media,
a drugi — za obsáugĊ systemu plików.
Nie powinna dziwiü duĪa liczba list uĪytych w tym projekcie. WiĊkszoĞü wyĞwietlaczy
musi daü uĪytkownikowi moĪliwoĞü wyboru — do tego najlepiej nadają siĊ wáaĞnie
listy. Dwie z nich mają staáe elementy — są zadeklarowane w powyĪszym listingu.
Pozostaáe dwie wczytują swoją zawartoĞü z systemu plików i RMS.
WiĊkszą czĊĞü konstruktora MIDletu zajmują instrukcje tworzące obiekty wyĞwietlaczy
i zaopatrujące je w polecenia. Pojawia siĊ przy tym ciekawa konstrukcja:
Rozdziaä 6. i Multimedia w Twoim telefonie
103
OdtwarzaczMIDlet.java
package pl.helion.j2mepp.odtwarzacz;
import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.*;
public class OdtwarzaczMIDlet extends MIDlet implements CommandListener
{
public OdtwarzaczMIDlet() throws Exception
{
menu = new List( Wybierz akcje: ,Choice.IMPLICIT,OPCJE,null);
Command wybierz = new Command( Wybierz ,Command.OK,0);
Command koniec = new Command( Koniec ,Command.EXIT,0);
Command powrot = new Command( Powrot ,Command.EXIT,0);
menu.addCommand(koniec);
menu.addCommand(wybierz);
menu.setSelectCommand(wybierz);
menu.setCommandListener(this);
formaHttp = new Form( Podaj adres URL: );
poleUrl = new TextField( , http:// ,150,TextField.ANY);
formaHttp.append(poleUrl);
Command ok = new Command( OK ,Command.OK,0);
formaHttp.addCommand(ok);
formaHttp.addCommand(powrot);
formaHttp.setCommandListener(this);
listaFile = new List( Wybierz plik: ,List.IMPLICIT);
Command wejdz = new Command( Wejdz ,Command.ITEM,0);
Command wyjdz = new Command( Wyjdz ,Command.ITEM,1);
listaFile.addCommand(wejdz);
listaFile.addCommand(wyjdz);
listaFile.addCommand(powrot);
listaFile.setSelectCommand(wejdz);
listaFile.setCommandListener(this);
listaPrzechwytujaca = new List( Przechwyc
´audio ,Choice.IMPLICIT,POLECENIA_PRZECHWYTYWANIA,null);
listaPrzechwytujaca.addCommand(powrot);
listaPrzechwytujaca.addCommand(wybierz);
listaPrzechwytujaca.setSelectCommand(wybierz);
listaPrzechwytujaca.setCommandListener(this);
listaRms = new List( Wybierz element: ,Choice.IMPLICIT);
listaRms.addCommand(wybierz);
listaRms.addCommand(powrot);
listaRms.setSelectCommand(wybierz);
listaRms.setCommandListener(this);
formaOdtwarzacz = new Form( Teraz odtwarzane... );
formaOdtwarzacz.append( );
formaOdtwarzacz.addCommand(powrot);
formaOdtwarzacz.setCommandListener(this);
formaAparat = new Form( Zrob zdjecie );
formaAparat.append( );
Command pstryk = new Command( Pstryk! ,Command.OK,0);
formaAparat.addCommand(powrot);
formaAparat.addCommand(pstryk);
formaAparat.setCommandListener(this);
odtwarzacz = new Odtwarzacz(this);
menadzer = new MenadzerPlikow(this);
104
J2ME. Praktyczne projekty
ekran = Display.getDisplay(this);
ekran.setCurrent(menu);
}
W powyĪszym kodzie znajdują siĊ dwie ciekawe, zastosowane po raz pierwszy kon-
strukcje. Polecenie o nazwie Wybierz pojawia siĊ w aplikacji wiele razy. Nie ma sensu
tworzyü takiego samego obiektu pod róĪnymi nazwami — jedna instancja klasy Command
moĪe byü dodana do róĪnych formularzy, o ile przy identyfikowaniu polecenia korzysta
siĊ z jego typu i priorytetu. Mimo Īe metoda setSelectCommand() jednoczeĞnie dodaje
polecenie (o ile nie zostaáo wczeĞniej jawnie dodane), to obiekt wybierz jest dodawany
rĊcznie w kodzie MIDletu, aby lepiej zobrazowaü liczbĊ zastosowanych do kaĪdej for-
matki poleceĔ.
Drugim intrygującym mechanizmem jest dodanie do formatek formaOdtwarzacz i forma
´Aparat pustych etykiet tekstowych. Tak naprawdĊ rodzaj dodanego komponentu nie
ma znaczenia — wywoáanie tego wariantu metody append() jest po prostu najkrótsze.
WaĪne jest, aby formatka miaáa jeden komponent. W trakcie dziaáania aplikacji owa pusta
etykieta tekstowa zostanie zastąpiona np. kontrolką wyĞwietlającą film.
Przed omówieniem najdáuĪszej metody zajmĊ siĊ krótkimi metodami pomocniczymi,
wykorzystywanymi przez pozostaáe klasy pakietu do dziaáaĔ na interfejsie MIDletu:
OdtwarzaczMIDlet.java
public void startApp() {}
public void pauseApp() {}
public void destroyApp(boolean u)
{
odtwarzacz.koniec();
}
public void wyswietlElementy(String[] wartosci)
{
listaFile.deleteAll();
for (int i=wartosci.length-1;i =0;i--)
listaFile.append(wartosci[i],null);
}
public void wlaczWyswietlacz(Item it)
{
if (it!=null)
formaOdtwarzacz.set(0,it);
else
formaOdtwarzacz.set(0,new StringItem( , ));
ekran.setCurrent(formaOdtwarzacz);
}
W momencie zakoĔczenia aplikacji odtwarzacz musi zwolniü wszystkie swoje zasoby.
Dwie pozostaáe metody przypominają te znane z poprzednich projektów. W metodzie
wyswietlElementy() dodajemy nowe elementy od koĔca tablicy, tak aby ostatni element
z tablicy znalazá siĊ na górze wyĞwietlanej listy. Druga z metod peáni kluczową rolĊ
przy odtwarzaniu filmów. Obiekt it zawiera obszar, w którym jest wyĞwietlany film.
Musi on zatem zostaü wyĞwietlony na formatce. Przy odtwarzaniu dĨwiĊków film nie
jest jednak potrzebny, dlatego stosujĊ pustą etykietĊ tekstową.
Rozdziaä 6. i Multimedia w Twoim telefonie
105
Metoda obsáugi zdarzeĔ w tym projekcie jest rozbudowana. Wynika to z duĪej liczby
zawartych w aplikacji wyĞwietlaczy i dostĊpnych poleceĔ. Jej opis jest podzielony na
kilka czĊĞci:
OdtwarzaczMIDlet.java
public void commandAction(Command c, Displayable s)
{
if (s == menu)
{
if (c.getCommandType() == Command.OK)
{
if (menu.getSelectedIndex() == 0)
ekran.setCurrent(formaHttp);
if (menu.getSelectedIndex() == 1)
{
menadzer.odswiez();
menadzer.wyswietlKorzenie();
ekran.setCurrent(listaFile);
}
if (menu.getSelectedIndex() == 2)
{
listaRms.deleteAll();
String[] numery = odtwarzacz.pobierzID();
for (int i=0;i numery.length;i++)
listaRms.append(numery[i],null);
ekran.setCurrent(listaRms);
}
if (menu.getSelectedIndex() == 3)
ekran.setCurrent(listaPrzechwytujaca);
if (menu.getSelectedIndex() == 4)
{
ekran.setCurrent(formaAparat);
Item it = odtwarzacz.pobierajObraz();
if (it!=null)
formaAparat.set(0,it);
}
}
if (c.getCommandType() == Command.EXIT)
{
this.destroyApp(true);
this.notifyDestroyed();
}
}
W metodzie tej moĪna znaleĨü wiele odwoáaĔ do obiektów menadzer i odtwarzacz.
Istotą obsáugi zdarzeĔ listy-menu jest wyĞwietlanie innych formatek. Niektóre z nich
wymagają jednak wczeĞniejszego przygotowania. Tak jest w przypadku listy lista
´Plikow, która wyĞwietla listĊ katalogów i plików. Przed pierwszym wyĞwietleniem
program musi pobraü listĊ korzeni systemu plików (ang. root) — szerzej zostanie to
omówione nieco dalej. Nie inaczej jest, gdy pobieramy spis nagraĔ z RMS. Po uprzed-
nim wyczyszczeniu listy i pobraniu identyfikatorów nastĊpuje wyĞwietlenie elementów.
Wreszcie formatka formaAparat otrzymuje obiekt wyĞwietlający obraz z kamery tele-
fonu i ustawia go jako komponent — teraz widoczne jest zastosowanie jednej z pustych
etykiet tekstowych. Obsáuga zdarzeĔ kolejnych wyĞwietlaczy jest zróĪnicowana:
106
J2ME. Praktyczne projekty
OdtwarzaczMIDlet.java
if (s == formaHttp)
{
if (c.getCommandType() == Command.OK)
if (!poleUrl.getString().equals( ))
{
odtwarzacz.przygotuj(poleUrl.getString());
}
if (c.getCommandType() == Command.EXIT)
ekran.setCurrent(menu);
}
if (s == listaFile)
{
if (c.getCommandType() == Command.ITEM)
{
try
{
if (c.getPriority()==0)
{
int k = listaFile.getSelectedIndex();
if (k -1)
{
menadzer.przejdzDo(listaFile.getString(k));
if (menadzer.jestKatalog())
{
String[] wyniki = menadzer.zwrocZawartosc();
this.wyswietlElementy(wyniki);
} else
{
odtwarzacz.przygotuj(menadzer.pobierzSciezke());
}
}
}
if (c.getPriority()==1)
{
menadzer.wyjdzDoGory();
String[] wyniki = menadzer.zwrocZawartosc();
this.wyswietlElementy(wyniki);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
if (c.getCommandType() == Command.EXIT)
{
ekran.setCurrent(menu);
}
}
Obsáuga formatki wczytującej plik z internetu jest banalna — wszystkim zajmuje siĊ
metoda przygotuj(). Zdecydowanie bardziej záoĪona jest konstrukcja obsáugująca sys-
tem plików. Polecenia są tylko dwa: Wejdz (priorytet 0) i Wyjdz (priorytet 1). Pierw-
sze z nich jest gotowe zarówno na sytuacjĊ, w której zaznaczony obiekt jest folderem,
jak i plikiem. Metoda zwrocZawartosc() pobiera listĊ katalogów i plików aktualnego
Rozdziaä 6. i Multimedia w Twoim telefonie
107
katalogu, okreĞlonego za pomocą metody przejdzDo(). JeĞli mamy do czynienia z pli-
kiem, wtedy próbujemy go odtworzyü. Rozszerzenie tego moduáu, aby sprawdzaá zawar-
toĞü plików przed próbą odtworzenia, czytelnik moĪe potraktowaü jako üwiczenie roz-
szerzające funkcjonalnoĞü programu. Prostszą czynnoĞcią jest przejĞcie do katalogu
wyĪszego rzĊdu.
OdtwarzaczMIDlet.java
if (s == listaRms)
{
if (c.getCommandType() == Command.OK)
if (listaRms.getSelectedIndex() -1)
odtwarzacz.przygotuj( rms:// +listaRms.getString
´(listaRms.getSelectedIndex()));
if (c.getCommandType() == Command.EXIT)
ekran.setCurrent(menu);
}
if (s == formaOdtwarzacz)
{
if (c.getCommandType() == Command.EXIT)
{
ekran.setCurrent(menu);
odtwarzacz.przerwij();
}
}
if (s == formaAparat)
{
if (c.getCommandType() == Command.OK)
{
try
{
odtwarzacz.pobierzZdjecie();
}
catch (Exception e)
{
e.printStackTrace();
}
}
if (c.getCommandType() == Command.EXIT)
{
ekran.setCurrent(menu);
odtwarzacz.przerwij();
}
}
NastĊpna lista, przechowująca spis nagranych multimediów, korzysta w adresie z pro-
tokoáu o nazwie rmsp , utworzonego na potrzeby tej aplikacji. W rzeczywistoĞci chodzi
o sprecyzowanie jednego systemu przekazywania danych do metody przygotuj().
Obiekt menedĪera pobiera identyfikator rekordu, który znajduje siĊ za definicją proto-
koáu, a nastĊpnie na jego podstawie wczytuje wáaĞciwy rekord. Forma formaOdtwarzacz
musi zadbaü o przerwanie odtwarzania w chwili, gdy uĪytkownik wybierze polecenie
Wyjdz. Utworzenie zdjĊcia za pomocą formatki formaAparat wymaga wywoáania tylko
jednej metody — wszystkie szczegóáy implementacyjne są zawarte w klasach Odtwarzacz
i CzytnikDanych.
108
J2ME. Praktyczne projekty
OdtwarzaczMIDlet.java
if (s == listaPrzechwytujaca)
{
if (c.getCommandType() == Command.OK)
{
if (listaPrzechwytujaca.getSelectedIndex() == 0)
odtwarzacz.przechwyc(true);
if (listaPrzechwytujaca.getSelectedIndex() == 1)
odtwarzacz.przechwyc(false);
if (listaPrzechwytujaca.getSelectedIndex() == 2)
odtwarzacz.odtworzNagranie();
if (listaPrzechwytujaca.getSelectedIndex() == 3)
try
{
odtwarzacz.zapisz( audio/x-wav );
}
catch (Exception e)
{
e.printStackTrace();
}
}
if (c.getCommandType() == Command.EXIT)
{
odtwarzacz.przechwyc(false);
ekran.setCurrent(menu);
}
}
}
Ostatnia z list udostĊpnia sporą paletĊ czynnoĞci. Metoda przechwyc() rozpoczyna lub
zatrzymuje nagrywanie, zgodnie z wartoĞcią przekazanego parametru. Warto zwróciü
uwagĊ na metodĊ zapisz() z klasy Odtwarzacz. Operacja zapisu wymaga podania typu
MIME, jaki ma byü okreĞlony dla nagrania. Na jego podstawie moĪna wywnioskowaü,
w jaki sposób multimedia stworzone przez uĪytkownika są przechowywane w RMS. OtóĪ
kaĪdy rekord skáada siĊ z dwóch czĊĞci: zawartoĞci oraz nazwy typu MIME. DziĊki
temu moĪna przechowywaü róĪnego rodzaju zawartoĞü, która dziĊki zapamiĊtanemu
typowi MIME moĪe byü prawidáowo rozpoznana przez odtwarzacz.
W trakcie testowania nie naleĪy martwiü siĊ obrazem, który znajduje siĊ na ekranie
emulatora — w prawdziwym urządzeniu w tym miejscu znajdowaáby siĊ aktualny obraz
kamery.
Odtwarzacz a FileConnection Optional Package
Zanim omówiĊ multimedialny aspekt naszej aplikacji, postaram siĊ przybliĪyü funkcjo-
nowanie systemu plików w telefonach komórkowych. NastĊpnie opiszĊ klasĊ Menadzer
´Plikow, która w naszym MIDlecie odpowiada za przeglądanie struktury katalogów
i wybór plików do odtwarzania.
Rozdziaä 6. i Multimedia w Twoim telefonie
109
Prawie jak PC
API definiujące wykonywanie operacji na plikach jest zawarte w JSR-75. Pakiet odpo-
wiedzialny za obsáugĊ plików to javax.microedition.io.file. Zawiera on piĊü elemen-
tów, jednak z punktu widzenia naszej aplikacji najwaĪniejsze są dwa:
interfejs FileConnection umoĪliwiający otwieranie plików, przeglądanie
zawartoĞci katalogów i inne podstawowe operacje,
klasa FileSystemRegistry, która m.in. udostĊpnia listĊ korzeni systemu plików
urządzenia.
Dwa razy w tym rozdziale pojawiáo siĊ sáowo „korzeĔ”. Jak sama nazwa wskazuje, jest
on czymĞ podstawowym; moĪna porównaü go do partycji systemu Windows (np. c:, d:).
Korzenie mogą wskazywaü na foldery znajdujące siĊ w pamiĊci telefonu, ale mogą teĪ
dotyczyü np. udostĊpnionych kart pamiĊci1.
ObecnoĞü powyĪszych elementów JSR-75 w pakiecie javax.microedition.io.file
oraz charakterystyczna nazwa interfejsu pozwalają przypuszczaü, Īe proces korzystania
z systemu plików jest podobny do nawiązywania poáączenia z internetem. Tak faktycz-
nie jest; jedyną róĪnicą, poza stosowanym interfejsem, jest skáadnia adresu, za pomocą
którego są lokalizowane pliki i katalogi. Przykáadowy adres wygląda tak:
file:///root1/filmy/film.mpg
Pierwsze szeĞü znaków, czyli file://, stanowi okreĞlenie protokoáu. NastĊpnie widzimy
nazwĊ korzenia (/root1) oraz ĞcieĪkĊ do pliku wraz z jego nazwą (/filmy/film.mpg).
Nawiązaü poáączenie z danym plikiem lub katalogiem moĪna nawet wtedy, gdy on
nie istnieje. MoĪna go wtedy utworzyü za pomocą metody create() lub mkdir(). JeĞli
jednak wczytywany zasób istnieje, sprawa jest prosta. W przypadku pliku wystarczy
odwoáaü siĊ do wiedzy z rozdziaáu 4. i wywoáaü metodĊ openInputStream(). TrochĊ
bardziej skomplikowanie wygląda sytuacja, gdy mamy do czynienia z katalogami. MoĪna
wywoáaü wtedy metodĊ list(), która zwraca listĊ wszystkich katalogów i plików
w okreĞlonej lokalizacji.
Jednak co powinniĞmy zrobiü, gdy chcemy wczytaü nowy plik lub sprawdziü zawartoĞü
innego katalogu? ChociaĪ w interfejsie FileConnection jest zadeklarowana metoda
setFileConnection(), to jest ona obwarowana licznymi zastrzeĪeniami (m.in. element
aktualnie wskazywany musi byü katalogiem, a nowy element musi istnieü w tym kata-
logu). Dlatego zaleca siĊ tworzenie nowego obiektu interfejsu FileConnection przy
dostĊpie do kaĪdego kolejnego elementu.
FileConnection Optional Package a uprawnienia dostöpu
Nie kaĪde urządzenie zezwala na peány zakres operacji w odniesieniu do udostĊpnianych
plików i katalogów. Tradycyjnie zakres Īądanych uprawnieĔ okreĞla siĊ w metodzie
open() klasy Connector. Staáe definiujące sposób dostĊpu są identyczne jak w przypadku
1 Na przykáad w telefonach wykorzystujących system Nokia OS pamiĊü wewnĊtrzna jest widziana jako C:,
a dodatkowa karta pamiĊci jako E:.
110
J2ME. Praktyczne projekty
poáączeĔ internetowych. W przypadku niemoĪnoĞci uzyskania Īądanego trybu dostĊpu
do pliku lub katalogu aplikacja zwraca wyjątek klasy SecurityException.
Tryb dostĊpu ma wpáyw na moĪliwoĞü wykonania metod klasy FileConnection. Dlatego
naleĪy uwaĪaü, czy w trybie tylko do odczytu (READ_ONLY) nasza aplikacja nie wywoáuje
metody openOutputStream() — taka operacja, jakkolwiek zostanie dopuszczona przez
kompilator, na pewno spowoduje wyjątek SecurityException.
Nie naleĔy uruchamiaè dwóch instancji tego samego emulatora wykorzystujñcych
FCOP API, poniewaĔ moĔe dojĈè do bäödów w wykonywaniu operacji odczytu i zapisu.
Opis moĔliwoĈci FCOP
Metody udostĊpniane przez klasĊ i interfejs znajdują siĊ w poniĪszym zestawieniu.
javax.microedition.io.file.FileSystemRegistry
public static Enumeration listRoots() — zwraca wszystkie dostĊpne
w urządzeniu korzenie. Nazwy są przechowywane w postaci áaĔcuchów
w obiekcie wyliczeniowym.
javax.microedition.io.file.FileConnection
public long availableSize() — zwraca iloĞü dostĊpnego miejsca w korzeniu,
w którym znajduje siĊ plik lub katalog okreĞlony danym obiektem poáączenia.
public void create() — tworzy plik o ĞcieĪce okreĞlonej w danym obiekcie
poáączenia.
public void delete() — usuwa plik o ĞcieĪce okreĞlonej w danym obiekcie
poáączenia.
public boolean exists() — sprawdza, czy plik lub katalog okreĞlony w danym
obiekcie poáączenia istnieje.
public boolean isDirectory() — sprawdza, czy obiekt okreĞlony w poáączeniu
jest katalogiem.
public Enumeration list(String klucz, boolean czyUkryte) — zwraca
wszystkie pliki i katalogi znajdujące siĊ w katalogu okreĞlonym w danym
obiekcie poáączenia. Wszystkie elementy są filtrowane wedáug klucza (moĪna
zastosowaü znak *, oznaczający dowolny ciąg znaków); jeĞli parametr czyUkryte
ma wartoĞü true, metoda zwraca takĪe pliki i katalogi ukryte.
JeĈli emulator nie zwraca poprawnej zawartoĈci katalogu, naleĔy skasowaè plik in.use
z katalogu KATALOG /appdb/ emulator .
public void mkdir() — tworzy katalog o ĞcieĪce okreĞlonej w danym obiekcie
poáączenia.
Rozdziaä 6. i Multimedia w Twoim telefonie
111
public InputStream openInputStream() — zwraca strumieĔ wejĞcia (do odczytu)
dla okreĞlonego pliku.
public OutputStream openOutputStream() — zwraca strumieĔ wyjĞcia
(do zapisu) dla okreĞlonego pliku.
public void setFileConnection(String nazwa) — tworzy w danym obiekcie
poáączenie z nowym plikiem lub katalogiem i zastĊpuje nim aktualne.
public void truncate(long n) — usuwa wszystkie dane z pliku okreĞlonego
w poáączeniu, począwszy od n-tego bajtu.
Implementacja przeglñdarki systemu plików
w projekcie
Podsumujmy wnioski, które moĪna wyciągnąü z analizy MIDletu, a zwáaszcza metody
commandAction(), dotyczące wykorzystania w odtwarzaczu systemu plików:
Program ma moĪliwoĞü pobrania listy korzeni.
Program moĪe poruszaü siĊ po strukturze katalogów w obydwie strony (w gáąb
i do góry).
Program moĪe pobraü plik i udostĊpniü go obiektowi odtwarzacza.
Wszystkie metody potrzebne do wykonania powyĪszych czynnoĞci są zawarte w klasie
MenadzerPlikow.
Lista zmiennych klasy jest wyjątkowo krótka:
MenadzerPlikow.java
private FileConnection plik;
private OdtwarzaczMIDlet m;
private String sciezka = / ;
private static final String PRZED = file:// ;
}
Znaczenia zmiennej plik dla dziaáania klasy nie trzeba chyba táumaczyü. Zmienna
sciezka w poáączeniu ze staáą PRZEDROSTEK tworzy peáną ĞcieĪkĊ dostĊpu do pliku
i katalogu. Obiekt MIDletu jest potrzebny do wywoáania metod odĞwieĪających listĊ,
która przedstawia zawartoĞü aktualnego katalogu (listaPlikow).
Konstruktor zawiera bardziej interesującą konstrukcjĊ. Stosowane jest w nim sprawdze-
nie, czy urządzenie oferuje dostĊp do File API:
MenadzerPlikow.java
package pl.helion.j2mepp.odtwarzacz;
import javax.microedition.io.file.*;
import javax.microedition.io.*;
import java.util.*;
112
J2ME. Praktyczne projekty
import java.io.*;
public class MenadzerPlikow
{
public MenadzerPlikow(OdtwarzaczMIDlet _m) throws Exception
{
m = _m;
String v = System.getProperty( microedition.io.file.FileConnection.version );
if (v==null)
throw new Exception( Brak obslugi systemu plikow! );
}
Metoda getProperty() klasy System sáuĪy do pobierania wáaĞciwoĞci maszyny wirtu-
alnej i zwraca null, jeĞli wáaĞciwoĞü o podanej nazwie nie istnieje. JeĞli tak siĊ stanie
w naszym przypadku, zostanie wygenerowany wyjątek. Pierwsza z metod to metoda
wyswietlKorzenie():
MenadzerPlikow.java
public void wyswietlKorzenie()
{
new Thread(new Runnable(){
public void run()
{
Enumeration zestaw = FileSystemRegistry.listRoots();
String[] rooty = przerobEnumerationNaString(zestaw);
m.wyswietlElementy(rooty);
}
}).start();
}
W powyĪszej metodzie po raz pierwszy zostaáa zastosowana konstrukcja tworząca i uru-
chamiająca nowy wątek w taki sposób. Korzystamy z jednego z konstruktorów klasy
Thread:
public Thread(Runnable watek)
oraz z faktu, Īe Java umoĪliwia utworzenie anonimowego obiektu interfejsu, o ile zostaną
zadeklarowane wszystkie jego metody. W naszej sytuacji wystarczy utworzyü metodĊ
run(). Dlaczego jednak tworzymy dla tej czynnoĞci nowy wątek?
Wykonanie niektórych czynnoĞci, zwáaszcza związanych z wykorzystaniem zewnĊtrz-
nych zasobów, wymaga zezwolenia. Uzyskuje siĊ je na dwa sposoby:
przez cyfrowe podpisanie MIDletu; wymaga to jednak uzyskania certyfikatu
autentycznoĞci z któregoĞ z dozwolonych centrów autentykacji — jest to proces
stosunkowo dáugi i drogi, zwáaszcza w Polsce;
przez wyĞwietlenie komunikatu i bezpoĞrednią zgodĊ uĪytkownika.
JeĞli uĪytkownik zezwoli na daną czynnoĞü, aplikacja wykonuje kolejne instrukcje;
w przeciwnym razie zgáaszany jest wyjątek klasy SecurityException. Niestety, emula-
tor oraz niektóre modele telefonów na pytanie o dostĊp reagują zawieszeniem programu,
gdy pytanie pojawia siĊ w metodzie obsáugi poleceĔ. W związku z tym wszystkie
metody, które mogą spowodowaü wyĞwietlenie komunikatu, powinny byü wywoáywane
w nowych wątkach.
Rozdziaä 6. i Multimedia w Twoim telefonie
113
ProĞba o pozwolenie jest wyĞwietlana zazwyczaj tylko za pierwszym razem — póĨniej
program pamiĊta decyzjĊ uĪytkownika. W związku z tym nie trzeba zabezpieczaü wszyst-
kich metod. W klasie MenadzerPlikow wiadomo, Īe to metoda wyswietlKorzenie() zawsze
jako pierwsza prosi o dostĊp, tak wiĊc tylko ona musi byü uruchamiana w nowym wątku.
Metoda ta wykorzystuje metodĊ listRoots() klasy FileSystemRegistry. Przy uĪyciu
pomocniczej metody przerobEnumerationNaString() program uzyskuje tablicĊ áaĔcu-
chów z obiektu wyliczeniowego. Dysponując tablicą nazw korzeni, moĪna wyĞwietliü
je za pomocą metody wyswietlElementy().
Metoda przerobEnumerationNaString() wykorzystuje wektor:
MenadzerPlikow.java
public String[] przerobEnumerationNaString(Enumeration e)
{
Vector lista = new Vector();
while (e.hasMoreElements())
lista.addElement(e.nextElement());
String[] wyniki = new String[lista.size()];
for (int i=0;i wyniki.length;i++)
wyniki[i] = (String)lista.elementAt(i);
return wyniki;
}
Na początku przeksztaácamy obiekt wyliczeniowy na wektor, aby nastĊpnie zamieniü go
na tablicĊ áaĔcuchów. Dlaczego wykorzystujemy dodatkowy wektor do utworzenia
tablicy? Niestety, klasa Enumeration nie ma metody zwracającej liczbĊ obiektów znaj-
dujących siĊ w danym obiekcie wyliczeniowym. Nie znając tej liczby, nie moĪna utwo-
rzyü tablicy. Z kolei klasa Vector taką metodĊ ma (size()).
NastĊpne metody wykorzystywane w klasie MIDletu odpowiadają za poruszanie siĊ po
strukturze katalogów. Są to metody przejdzDo() i wyjdzDoGory():
MenadzerPlikow.java
public void przejdzDo(String nazwa) throws Exception
{
sciezka += nazwa;
this.ustalPlik();
}
public void wyjdzDoGory() throws Exception
{
if (sciezka.length() 1)
{
if (this.jestKatalog())
{
sciezka = sciezka.substring(0,sciezka.length()-1);
int indeks = sciezka.lastIndexOf( / );
sciezka = sciezka.substring(0,indeks+1);
} else
{
int indeks = sciezka.lastIndexOf( / );
sciezka = sciezka.substring(0,indeks+1);
}
114
J2ME. Praktyczne projekty
if (sciezka.length() 1)
this.ustalPlik();
}
}
Metoda wchodząca w gáąb struktury katalogów jest uniwersalna. DziĊki temu skáada
siĊ tylko z dwóch linijek kodu. Po zmianie bieĪącej ĞcieĪki wywoáywana jest metoda
ustalPlik(). To wáaĞnie ona tworzy nowy obiekt poáączenia z plikiem lub katalogiem.
Druga z metod zawiera jedynie operacje na áaĔcuchach. ĝcieĪki do katalogu i pliku
róĪnią siĊ jednym, ale waĪnym detalem: pierwsza z nich zawiera na koĔcu znak /
(ukoĞnik). W przypadku katalogu w pierwszej instrukcji pozbywamy siĊ wáaĞnie tego
koĔcowego ukoĞnika. NastĊpnie znajdujemy ostatni ukoĞnik i usuwamy wszystko, co
siĊ za nim znajduje (czyli nazwĊ katalogu, z którego chcemy wyjĞü). W przypadku pliku
sposób postĊpowania jest podobny, z wyjątkiem usuwania koĔcowego ukoĞnika.
Kluczową metodą tej klasy jest metoda ustalPlik(). Nawiązuje ona poáączenie z plikiem
i sprawdza, czy plik istnieje. JeĞli nie — zwraca wyjątek:
MenadzerPlikow.java
private void ustalPlik() throws IOException
{
if (plik!=null)
plik.close();
plik = (FileConnection)Connector.open(this.pobierzSciezke(),Connector.READ);
if (!plik.exists())
throw new IOException( Brak pliku! );
}
Parametr przekazany metodzie open() jest pobierany za pomocą pomocniczej metody,
wprowadzonej, aby budowanie peánego adresu odbywaáo siĊ w jednym miejscu w kodzie.
Metoda zwrocZawartosc() to ostatnia waĪna i funkcjonalna metoda w tej klasie:
MenadzerPlikow.java
public String[] zwrocZawartosc() throws IOException
{
if (sciezka.length()==1)
return this.przerobEnumerationNaString(FileSystemRegistry.listRoots());
this.ustalPlik();
if (plik.isDirectory())
{
Enumeration list = plik.list();
String[] wyniki = this.przerobEnumerationNaString(list);
return wyniki;
} else
return null;
}
JeĞli program chce zwróciü listĊ elementów początkowego katalogu (który zawiera
zbiór korzeni), trzeba wywoáaü metodĊ listRoots(). W przeciwnym wypadku metoda
ustala obecną ĞcieĪkĊ. NastĊpnie, w przypadku gdy bieĪąca ĞcieĪka prowadzi do kata-
logu, zwracana jest lista jego elementów. W przeciwnym razie zwracana jest wartoĞü null.
Rozdziaä 6. i Multimedia w Twoim telefonie
115
Ostatnie trzy metody mają charakter pomocniczy. Ich treĞü moĪna wydedukowaü na
podstawie wczeĞniejszych metod i FCOP API:
MenadzerPlikow.java
public String pobierzSciezke()
{
return PRZED+sciezka;
}
public void odswiez()
{
sciezka = / ;
}
public boolean jestKatalog()
{
if (plik!=null)
return plik.isDirectory();
else
return false;
}
Metoda pobierzSciezke() áączy dwie kluczowe czĊĞci adresu: protokóá i wáaĞciwą
ĞcieĪkĊ. Metoda odswiez() ma za zadanie przywróciü domyĞlną wartoĞü ĞcieĪki (przy
powtórnym przeglądaniu zawartoĞci systemu plików). Ostatnia metoda sprawdza, czy
plik istnieje, i dopiero wtedy zwraca wartoĞü metody isDirectory(). W przeciwnym
wypadku zwraca wartoĞü false.
Obsäuga multimediów w odtwarzaczu
Nieuchronnie zbliĪamy siĊ do momentu, gdy omówiĊ najwiĊkszą klasĊ, z jaką dotąd siĊ
spotkaliĞmy. Klasa Odtwarzacz, bo o niej mowa, zawiera wszystkie funkcje związane
z pakietem javax.microedition.media. Proces obsáugi danych zostaá wydzielony do klasy
CzytnikDanych.
Na wstĊpie bardzo waĪna informacja: nasz odtwarzacz nie implementuje wielu kon-
trolek, które są związane z procesem odtwarzanialnych. Moim celem w tym projekcie
byáo zaprezentowanie istoty odtwarzania treĞci multimedialnych — obsáuga poszcze-
gólnych kontrolek jest prosta i sprowadza siĊ w duĪej mierze do zapoznania siĊ z ich
metodami.
ZacznĊ, jak zwykle, od listy zmiennych — równieĪ doĞü obszernej i zróĪnicowanej:
Odtwarzacz.java
private Player p;
private OdtwarzaczMIDlet m;
private VideoControl vc;
private VideoControl aparat;
private RecordControl rc;
private ByteArrayOutputStream baos;
private String sciezka;
private CzytnikDanych czytnik;
private byte[] bufor = new byte[0];
116
J2ME. Praktyczne projekty
private boolean tryb;
private boolean nagrywa = false;
private String typZdjecia;
}
Obiekt p jest najczĊĞciej wykorzystywany w caáej klasie — to on peáni rolĊ odtwarzacza.
Zastanawiaü mogą aĪ dwie kontrolki wideo: vc i aparat. Jest to spowodowane koniecz-
noĞcią uĪycia osobnych obiektów do odtwarzania i przechwytywania obrazu z aparatu.
Znaczenie pozostaáych zmiennych bĊdĊ przybliĪaü przy omawianiu konkretnych metod.
NaleĪy zwróciü uwagĊ na obiekt klasy CzytnikDanych, gdyĪ to wáaĞnie w nim bĊdzie
zawarty proces wczytywania danych. Po raz pierwszy stosujemy go juĪ w konstruktorze:
Odtwarzacz.java
package pl.helion.j2mepp.odtwarzacz;
import javax.microedition.media.*;
import javax.microedition.media.control.*;
import java.io.*;
import javax.microedition.lcdui.*;
public class Odtwarzacz
{
public Odtwarzacz(OdtwarzaczMIDlet p_m)
{
m = p_m;
czytnik = new CzytnikDanych(p_m);
typZdjecia = this.pobierzDomyslnyTyp();
}
Obiekt czytnika równieĪ wymaga odwoáania do klasy MIDletu — ze wzglĊdu na
koniecznoĞü zamkniĊcia aplikacji w przypadku báĊdu pobierania danych — ale to
omówiĊ szczegóáowo w swoim czasie. Zmienna typZdjecia przechowuje identyfikator
formatu, w jakim zapisywane bĊdą zdjĊcia z aparatu. Pomocnicza metoda pobierzDo
´myslnyTyp() wykorzystuje wáaĞciwoĞü maszyny wirtualnej o nazwie video.snapshot.
´encodings:
Odtwarzacz.java
public String pobierzDomyslnyTyp()
{
String typy = System.getProperty( video.snapshot.encodings );
if (typy.indexOf( jpeg ) -1)
return encoding=jpeg ;
if (typy.indexOf( png ) -1)
return encoding=png ;
if (typy.indexOf( gif ) -1)
return encoding=gif ;
return null;
}
Ponownie wykorzystujemy metodĊ System.getProperty(). àaĔcuch typy przybiera
nastĊpującą postaü:
Rozdziaä 6. i Multimedia w Twoim telefonie
117
encoding=jpeg encoding=png
Analogicznie, parametr okreĞlający typ zdjĊcia dla wykonującej je metody musi mieü
format encoding=xxx, gdzie xxx to nazwa typu. Jak widaü, wáaĞciwoĞü video.snap
´shot.encodings zawiera szereg poprawnie okreĞlonych kodowaĔ; trzeba tylko wy-
braü typ. Priorytety wybieranych formatów zaleĪą od kolejnoĞci instrukcji if w metodzie.
Mimo Īe emulator obsáuguje dwa typy zdjĊü, instrukcja sprawdzająca typ jpeg wystĊ-
puje jako pierwsza i to wáaĞnie przy uĪyciu typu JPEG zdjĊcie zostanie zapisane.
NajczĊĞciej pojawiającą siĊ w kodzie MIDletu metodą jest przygotuj(). Pobiera ona
za pomocą obiektu czytnik dane wymagane przez odtwarzacz, a nastĊpnie rozpoczyna
proces odtwarzania:
Odtwarzacz.java
public void przygotuj(String p_sciezka)
{
sciezka = p_sciezka;
new Thread(new Runnable(){
public void run()
{
try
{
p = czytnik.analizuj(sciezka);
if (p!=null)
{
p.realize();
if (p.getContentType().equals( video/mpeg ))
tryb = true;
else
tryb = false;
odtwarzaj();
} else
if (jestObrazek(czytnik.getTyp()))
{
Image obraz = Image.createImage(czytnik.getStrumien());
ImageItem it = new ImageItem( ,obraz,ImageItem.LAYOUT_CENTER, );
m.wlaczWyswietlacz(it);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}).start();
}
Na początku musimy przygotowaü obiekt odtwarzacza, czym zajmuje siĊ specjalna
metoda klasy Odtwarzacz. JeĞli obiekt odtwarzacza nie obsáuguje danego medium,
zwracana jest wartoĞü null i moĪemy sprawdziü, czy dane Ĩródáo nie okreĞla obrazka.
JeĞli tak — pobieramy jego strumieĔ i moĪemy wyĞwietliü go za pomocą komponentu
ImageItem. JeĞli zaĞ odtwarzacz napotka na „klasyczny” plik multimedialny, naleĪy
okreĞliü rodzaj medium — audio lub wideo — i przystąpiü do odtwarzania.
118
J2ME. Praktyczne projekty
Wywoäania metod klasy Odtwarzacz w anonimowym obiekcie interfejsu Runnable nie
zawierajñ säowa kluczowego this (np. odtwarzaj() zamiast this.odtwarzaj()),
poniewaĔ säowo this uĔyte w tym kontekĈcie oznaczaäoby odwoäanie do obiektu inter-
fejsu Runnable, a nie do obiektu klasy zewnötrznej.
Zajmijmy siĊ teraz metodą odtwarzaj(), która jest wywoáywana w metodzie przygotuj():
Odtwarzacz.java
public boolean odtwarzaj()
{
Item it = null;
if (tryb p!=null p.getState() == Player.REALIZED)
{
vc = (VideoControl)p.getControl( VideoControl );
if (vc!=null)
{
it = (Item)vc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE,null);
}
}
if (p!=null p.getState() == Player.REALIZED)
{
try
{
m.wlaczWyswietlacz(it);
p.prefetch();
p.start();
return true;
}
catch (MediaException me)
{
me.printStackTrace();
}
return false;
} else
return false;
}
PowyĪsza metoda swoje dziaáanie uzaleĪnia od zmiennej tryb. Gdy mamy do czynienia
z plikiem wideo (tryb=true), metoda przypisuje do komponentu it wyĞwietlacz wideo.
Odtwarzacz bĊdący w stanie REALIZED moĪe zwróciü kontrolkĊ interfejsu VideoControl.
NastĊpnie wywoáywana jest metoda initDisplayMode(), która zwraca obiekt wyĞwie-
tlacza wideo. Po wykonaniu opcjonalnej czĊĞci metody związanej z odtwarzaniem wideo
metoda próbuje ustawiü komponent graficzny (jeĞli odtwarzany jest plik audio, wtedy
it==null i metoda wlaczWyswietlacz() nie wykona Īadnej operacji), a nastĊpnie roz-
poczyna odtwarzanie pliku.
Odtwarzanie, zwäaszcza plików wideo, to proces wymagajñcy uĔycia duĔej iloĈci
pamiöci. NaleĔy pamiötaè, Ĕe odtwarzanie duĔych plików wideo moĔe spowodowaè
bäñd krytyczny maszyny wirtualnej i w konsekwencji przerwanie dziaäania aplikacji.
Rozdziaä 6. i Multimedia w Twoim telefonie
119
javax.microedition.media.control.VideoControl
public Object initDisplayMode(int tryb, Object argument) — zwraca
obiekt zawierający wyĞwietlany obraz. Wykorzystuje okreĞlony parametrem
tryb (USE_GUI_PRIMITIVE albo USE_DIRECT_VIDEO) wraz z dodatkowym
argumentem, którego znaczenie zaleĪy od wartoĞci pierwszego parametru:
USE_GUI_PRIMITIVE — w tym trybie metoda zwróci obiekt, który moĪe
stanowiü element GUI; w praktyce oznacza to, Īe bĊdzie on dziedziczyá
z klasy Item i bĊdzie go moĪna dodaü do formy.
USE_DIRECT_VIDEO — w tym trybie argument musi byü obiektem klasy Canvas
(lub dziedziczącym z niej), a metoda zwraca null; wyĞwietlany obraz jest
bezpoĞrednio rysowany w obszarze podanego obiektu.
javax.microedition.media.Manager
public static String[] getSupportedContentTypes(String protokol)
— zwraca listĊ typów MIME obsáugiwanych przez odtwarzacz dla danego
protokoáu.
Nagrywanie dĒwiöku
W kodzie klasy MIDletu dwa razy jest wykorzystywana metoda przechwyc(). W przy-
padku rejestrowania dĨwiĊku lub obrazu pozwolenie na wykonanie takiej czynnoĞci
jest jednorazowe. KaĪda kolejna próba nagrania powoduje wyĞwietlenie pytania o pozwo-
lenie (tak dzieje siĊ w przypadku emulatora; poszczególne modele telefonów mogą
róĪniü siĊ pod tym wzglĊdem). W związku z tym próba rozpoczĊcia nagrania wymaga
umieszczenia w nowym wątku:
Odtwarzacz.java
public void przechwyc(boolean czyStart)
{
try
{
if (czyStart)
{
if (!nagrywa)
new Thread(new Runnable(){
public void run()
{
try
{
baos = new ByteArrayOutputStream();
p = Manager.createPlayer( capture://audio );
p.realize();
rc = (RecordControl)p.getControl( RecordControl );
rc.setRecordStream(baos);
rc.startRecord();
p.start();
nagrywa = true;
} catch (Exception e){}
120
J2ME. Praktyczne projekty
}
}).start();
} else
{
if (nagrywa)
{
nagrywa = false;
rc.commit();
p.close();
bufor = baos.toByteArray();
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
Metoda przechwyc() obsáuguje zarówno rozpoczĊcie, jak i zakoĔczenie nagrania. Dodat-
kową rolĊ odgrywa zmienna klasy nagrywa; okreĞla ona stan, w jakim znajduje siĊ odtwa-
rzacz. DziĊki temu czĊĞü zatrzymująca nie zostanie wywoáana w stanie zatrzymania
(PREFETCHED) i odwrotnie.
Jak widaü, proces nagrywania jest realizowany z uĪyciem zarówno odtwarzacza, jak
i kontrolki nagrywającej, RecordControl. Po utworzeniu kontrolki w klasyczny spo-
sób — przy uĪyciu metody getControl() odtwarzacza znajdującego siĊ w stanie REALI
´ZED — naleĪy wywoáaü metodĊ setRecordStream(), która okreĞla strumieĔ odbiera-
jący dane z kontrolki nagrywającej. W tym momencie nie pozostaje nic innego, jak
rozpocząü nagrywanie i uruchomiü odtwarzacz.
Proces koĔczenia nagrywania jest prostszy: naleĪy zakoĔczyü dziaáanie kontrolki nagry-
wającej i odtwarzacza, a nastĊpnie wykorzystaü dane ze strumienia (my kopiujemy je do
zmiennej bufor).
javax.microedition.media.control.RecordControl
public void setRecordStream(OutputStream strumien) — ustawia strumieĔ
wyjĞcia, do którego zapisywane są dane z mikrofonu lub innego urządzenia
nagrywającego.
public void startRecord() — rozpoczyna nagrywanie, o ile odtwarzacz jest
w stanie STARTED.
public void stopRecord() — przerywa nagrywanie. Powoduje przejĞcie
kontrolki nagrywającej w stan wstrzymania. Aby ponownie wáączyü kontrolkĊ,
naleĪy wywoáaü metodĊ startRecord().
public void commit() — koĔczy nagrywanie. W przeciwieĔstwie do metody
stopRecord() po wywoáaniu tej metody nie moĪna ponownie wywoáaü metody
startRecord(). Wymaga to ustawienia nowego strumienia lub adresu
docelowego.
Rozdziaä 6. i Multimedia w Twoim telefonie
121
public void setRecordLocator(String url) — ustawia adres docelowy dla
zapisywanych danych na podany w parametrze. MoĪna stosowaü zamiennie
z metodą setRecordStream().
Odtwarzanie nagrania
Na obecnym etapie tworzenia klasy Odtwarzacz dysponujemy zmienną bufor, która
zawiera nagranie. NastĊpnym krokiem bĊdzie dodanie do niej dwóch metod wykorzy-
stujących tĊ zmienną w celu:
odtworzenia nagrania,
zapisu nagrania do RMS.
Pierwszą z funkcji realizuje metoda odtworzNagranie():
Odtwarzacz.java
public void odtworzNagranie()
{
if (!nagrywa bufor.length 0)
{
try
{
p = Manager.createPlayer(new ByteArrayInputStream(bufor), audio/x-wav );
p.realize();
p.prefetch();
p.start();
}
catch (Exception me)
{
me.printStackTrace();
}
}
}
Podstawowym warunkiem wykonania tej metody jest to, aby odtwarzacz nie zapisywaá
wáaĞnie Īadnych danych (nagrywa == false). Dodatkowym zabezpieczeniem przed
odtworzeniem nagrania jeszcze przed jego zarejestrowaniem (np. tuĪ po wyĞwietleniu
formatki) jest warunek bufor.length 0. Proces odtwarzania jest realizowany wedáug
standardowego schematu. Warto jednak zwróciü uwagĊ na parametry metody create
´Player(). Tablica jest ponownie przeksztaácana na strumieĔ; jednoczeĞnie wymu-
szamy standardowy typ audio, czyli audio/x-wav.
TreĞü drugiej z metod jest znacznie krótsza, gdyĪ wiĊkszoĞü implementacji zostaáa ujĊta
w klasie Czytnik:
Odtwarzacz.java
public void zapisz(String nazwa) throws Exception
{
if (!nagrywa bufor.length 0)
{
122
J2ME. Praktyczne projekty
czytnik.zapisz(nazwa,bufor);
bufor = new byte[0];
}
}
W metodzie zapisz()zostaáo zastosowane identyczne zabezpieczenie jak w metodzie
odtworzNagranie(). Metoda zapisz() obiektu czytnik zapisuje w nowym rekordzie
zarówno treĞü nagrania, jak i typ MIME.
Obsäuga aparatu
Ostatnią skomplikowaną funkcją multimedialną do zaprogramowania jest obsáuga aparatu
fotograficznego. RównieĪ ona skáada siĊ z dwóch etapów: zainicjalizowania dziaáania
aparatu oraz wykonania zdjĊcia. Pierwsza z tych czynnoĞci do záudzenia przypomina
odtwarzanie pliku wideo:
Odtwarzacz.java
public Item pobierajObraz()
{
Item obrazAparatu = null;
try
{
p = Man
Pobierz darmowy fragment (pdf)