Programowanie internetowe J2ME


Programowanie
J2ME
Programowanie internetowe
w J2ME
Krzysztof Rychlicki-Kicior
rogramiści lubią upraszczać sobie życie; gdzie otrzymujemy do dyspozycji interfejs Socket-
niestety, często przychodzi im zmagać się Connection. Do ważniejszych interfejsów MIDP 1.0
Pz zagadnieniami powszechnie uważany- zalicza się:
mi za obfitujące w potencjalne błędy. Pisanie apli-
kacji internetowych z pewnością zalicza się do tej " HttpConnection;
dziedziny  nie dość, że zamiast jednego progra- " ContentConnection;
mu trzeba napisać dwa, programista musi stwo- " StreamConnection;
rzyć język, przy pomocy którego obydwa progra- " DatagramConnection.
my będą się porozumiewać (najbardziej znane są
dostępne publicznie i noszą nazwę protokołów). W MIDP 2.0 dodano kolejne, jeszcze bardziej funk-
Do tego  pięknego obrazu trzeba jeszcze dodać cjonalne interfejsy:
problemy z komunikacją, które, zgodnie z prawa-
mi Murphy ego, zawsze pojawiają się w najmniej " HttpsConnection;
oczekiwanym momencie. Jednym z ciekawszych " CommConnection;
aspektów projektowania aplikacji komunikujących " UDPDatagramConnection;
się przy pomocy Internetu jest możliwość ich im- " SocketConnection.
plementacji w różnych językach programowania.
Niniejszy artykuł porusza kwestie związane z pi- Nawiązywanie połączenia
saniem tego rodzaju aplikacji na telefony komór- Stare indiańskie przysłowie mówi, że zanim za-
kowe. Wykorzystamy zatem język J2ME wraz piszesz lub wczytasz informacje z jakiegokolwiek
z oprogramowaniem J2ME Wireless Toolkit firmy zródła danych, musisz to zródło (w naszym przy-
Sun. Po krótkim zapoznaniu się z obsługą sieci padku połączenie) otworzyć. W J2ME do tego ce-
w J2ME napiszemy prosty telnet działający na te- lu używa się statycznej metody Connector.open().
lefonie komórkowym. Klasa Connector, podobnie jak wszystkie interfej-
sy do obsługi połączeń, znajduje się w pakiecie
Komórki i sieć javax.microedition.io. Zwraca ona obiekt typu
Pisząc programy na telefony komórkowe musimy Connection. Jest to interfejs bazowy dla wszyst-
pamiętać o kilku ważnych właściwościach tej plat- kich interfejsów sieciowych. Aby móc wykorzystać
formy sprzętowej. Chociaż obsługa połączeń sie- w pełni nawiązane połączenie, należy zrzutować
ciowych (w różnym zakresie, ale o tym pózniej) je na żądany typ interfejsu (np. HttpConnection lub
teoretycznie jest dostępna na wszystkich telefo- SocketConnection).
nach obsługujących Javę, nie każdy telefon ma  fi-
zycznie taką możliwość (dotyczy to głównie star- Kolejne czynności
szych modeli). Podstawowe komponenty do obsłu- Podobnie jak w przypadku innego rodzaju zasobów
gi Internetu są zawarte w MID Profile 1.0. Niestety, (np. plików w J2SE), do wczytywania i zapisywania
jedynym sensownym połączeniem, jakie możemy danych wykorzystuje się klasy strumieni. Dla pro-
utworzyć dysponującym tą wersją MIDP, jest połą- gramistów J2SE bolesnym może okazać się brak
czenie przy użyciu protokołu HTTP (interfejs Http- klasy BufferedReader, dzięki której można wczyty-
Connection). W praktyce oznacza to możliwość na- wać łańcuchy znaków (w postaci zmiennych typu
wiązania połączenia z dowolnym hostem tylko na String). Na szczęście projektanci Javy komórkowej
porcie 80. Problem ten znika wraz z MIDP 2.0, okazali się łaskawi przynajmniej w zakresie wysy-
łania danych  klasa PrintStream udostępnia meto-
dę println(), dzięki której możemy wysyłać łańcu-
Autor programuje w Javie i C# oraz tworzy aplikacje sie-
chy znaków. Oczywiście nie samymi tekstami żyje
ciowe w oparciu o technologię PHP i MySQL. Napisał
człowiek, w związku z czym otrzymujemy również
książkę pt.  J2ME. Java dla urządzeń mobilnych. Ćwi-
szeroki zakres metod do wysyłania liczb, wartości
czenia (Wydawnictwo Helion, 2006) oraz szereg ar-
logicznych, a przede wszystkim bajtów i tablic baj-
tykułów z zakresu Delphi, PHP i Javy. Prowadzi zaję-
tów. Po wykonaniu wszystkich wymaganych ope-
cia informatyczne z zakresu J2ME i C# dla młodzieży w
Aódzkim Centrum Doskonalenia Nauczycieli i Kształce- racji należy zamknąć gniazdko przy użyciu meto-
nia Praktycznego.
dy close(). Listing 1. zawiera program działający
Kontakt z autorem:kitikatpl@gmail.com
jak echo  jego zadaniem jest odsyłanie wszystkich
otrzymanych danych.
54
www.sdjournal.org
Software Developer s Journal 7/2006
Programowanie internetowe w J2ME
Telnet w komórce
Listing 1. Program wysyłający odebrane dane
Głównym celem niniejszego warsztatu jest napisanie pro-
import javax.microedition.lcdui.*; gramu przypominającego telnet na telefon komórkowy.
import javax.microedition.midlet.*; Przy jego tworzeniu uwzględnimy następujące reguły:
import java.io.*;
import javax.microedition.io.*; " polecenia tekstowe będą wysyłane wraz ze znakami po-
public class echo extends MIDlet wrotu karetki i nowej linii (\r\n) jako osobne porcje da-
{ nych (nie znak po znaku);
public echo() " odbierane będą pojedyncze łańcuchy znaków (zakończo-
{ ne znakiem nowej linii) lub dane otrzymane w przeciągu
try określonego czasu (jeśli nie zostanie nadesłany cały ciąg
{ znaków).
SocketConnection conn = (SocketConnection)Connector.open
("socket://domena.org:11111");
Listing 2. Tworzenie interfejsu formatek MIDletu
InputStream in = conn.openInputStream();
OutputStream out = conn.openOutputStream(); public class telnet extends MIDlet
int b; // Runnable posłuży do nawiązania połączenia
while ((b=in.read())!=-1) implements CommandListener,Runnable
{ {
out.write(b); public telnet()
} {
in.close(); // tworzymy interfejs pierwszej formatki
out.close(); dataform = new Form("Wpisz dane:");
conn.close(); host = new TextField("Host:","",30,TextField.ANY);
} port = new TextField("Port:","",5,TextField.NUMERIC);
catch (Exception e) dataform.append(host);
{ dataform.append(port);
e.printStackTrace(); dataform.setCommandListener(this);
} dataform.addCommand(new Command("Polacz",Command.OK,0));
} dataform.addCommand(new Command(
public void startApp(){} "Koniec",Command.EXIT,1));
public void pauseApp(){} sendform = new Form("Wyslij komunikat:");
public void destroyApp(boolean unconditional){} text = new TextField("Polecenie:","",150,TextField.ANY);
} sendform.append(text);
// wewnętrzna klasa zdarzenia
sendform.setCommandListener(new SendFormEvent());
W powyższym przykładzie wykorzystujemy podstawowe sendform.addCommand(new Command("Wyslij",Command.OK,0));
klasy strumieni  OutputStream i InputStream. Adres URL jest sendform.addCommand(new Command(
oczywiście zmyślony; program taki nie ma zresztą praktycz- "Podejrzyj",Command.EXIT,1));
nego zastosowania, ale dobrze pokazuje podstawowe me- mainform = new Form("Okno glowne:");
chanizmy funkcjonowania gniazdek w J2ME. mainform.setCommandListener(new MainFormEvent());
mainform.addCommand(new Command("Powrot",Command.OK,0));
mainform.addCommand(new Command(
"Zamknij",Command.EXIT,1));
display = Display.getDisplay(this);
display.setCurrent(dataform);
// jednocześnie będzie wyświetlane maksymalnie 5
// komunikatów
messages = new String[5];
// do tego celu wykorzystamy utworzone w tym fragmencie
// etykiety
labels = new StringItem[5];
for (int i=0;i<5;i++)
{
messages[i] = "";
labels[i] = new StringItem("","");
mainform.append(labels[i]);
}
}
Rysunek 1. Interfejs formy formadane
Software Developer s Journal 7/2006 www.sdjournal.org
55
Programowanie
J2ME
Przy tworzeniu połączenia należy zwrócić uwagę na waż-
Listing 3. Zdarzenie wybrania polecenia (formatka
ny fakt  jest to czynność dość czasochłonna, w związku
dataform)
z czym nie należy umieszczać ich w metodach zdarzeń ta-
// zdarzenie kich jak commandAction(). Bez przeszkód można jednak użyć
public void commandAction(Command c, Displayable s) wątków. W J2ME wykorzystuje się dwa klasyczne sposo-
{ by tworzenia wątków: utworzenie klasy pochodnej od klasy
if (c.getCommandType() == Command.EXIT) Thread oraz utworzenie klasy implementującej interfejs
{ Runnable. W naszej sytuacji najprościej jest zaimplementować
destroyApp(true); interfejs Runnable w klasie MIDletu (Listing 2.) i zadeklarować
notifyDestroyed(); // zakończ aplikację metodę run(). Jej zadaniem jest utworzenie połączenia oraz
} obiektów strumieni, a także rozpoczęcie procesu odbierania
if (c.getCommandType() == Command.OK) danych w specjalnym wątku.
{
Thread thread = new Thread(this); Transmisja danych
thread.start(); // uruchom wątek tworzący połączenie Po nawiązaniu połączenia nadszedł czas, aby zająć się od-
} bieraniem i wysyłaniem danych. Klasa Receiver ma za zada-
} nie wczytywać całe linijki tekstu, zakończone sekwencją zna-
ków o kodach 13 i 10 (znaki nowej linii i powrotu karetki). Goto-
wy tekst będzie dodawany do formularza mainform.
Interfejs programu Trzeba jednak być przygotowanym na odbieranie danych
Nasz MIDlet składa się z trzech formatek (pojemników klasy binarnych, które nie są zakończone powyższymi znakami.
Form, zwanych też formami lub formularzami). Pierwsza z nich W takiej sytuacji, timer zdarzenia ScreenPrinter będzie co se-
(o nazwie dataform) zawiera dwa pola tekstowe (TextField),
służące do wprowadzenia nazwy hosta i portu, na którym zo-
Listing 4. Metoda nawiązująca połączenie
stanie nawiązane połączenie. Działanie programu sprowa-
dza się do wprowadzania poleceń do pola tekstowego, znaj- public void run()
dującego się w drugiej formatce (sendform), wysyłania ich i od- {
bierania odpowiedzi serwera (formatka mainform). W Listingu int portnumer = Integer.parseInt(port.getString());
2. znajduje się początkowy fragment kodu, zawierający kon- try
struktor klasy MIDletu. {
Pamięć emulatora, podobnie jak prawdziwych urządzeń, // połączenia przy użyciu protokołu http muszą być
ma pewne ograniczenia. Dotyczy to zwłaszcza możliwości // obsługiwane przy pomocy interfejsu HttpConnection
przechowywania na jednej formatce komponentów. Program if (portnumer == 80)
mógłby po prostu dodawać każde otrzymane polecenie jako conn = (HttpConnection)Connector.open(
nową etykietę (StringItem). Niestety, wskutek owych ograni- "http://"+host.getString()+":80",
czeń musimy wprowadzić stałą liczbę etykiet i wykorzystać Connector.READ_WRITE,false);
metodę SetString() klasy StringItem do zmiany ich wartości. else // reszta połączeń jest obsługiwana normalnie
Pierwszą czynnością, jaką musimy się zająć jest utwo- conn = (SocketConnection)Connector.open(
rzenie połączenia. Musi ono nastąpić w wyniku wybrania od- "socket://"+host.getString()+":"+port.getString(),
powiedniego polecenia (Polacz). Związana z nim jest me- Connector.READ_WRITE,false);
toda commandAction()  dzięki implementowaniu interfejsu in = conn.openInputStream();
CommandListener przez nasz MIDlet możemy zadeklarować ją out = new PrintStream(conn.openOutputStream());
jako zwykłą metodą w klasie MIDletu (pózniej pokażemy, w ja- // wątek odbierania danych
ki sposób można inaczej utworzyć klasę zdarzenia). Thread thread = new Thread(new Receiver());
thread.start();
// timer odpowiedzialny za wypisywanie danych
// w sytuacji, gdy nie są przesyłane całe łańcuchy
// znaków
Timer timer = new Timer();
timer.schedule(new ScreenPrinter(),0,1000);
display.setCurrent(sendform);
}
catch (IOException e)
{
e.printStackTrace();
destroyApp(true);
notifyDestroyed();
}
}
Rysunek 2. Prośba MIDletu o pozwolenie na połączenie z
Internetem
56
www.sdjournal.org
Software Developer s Journal 7/2006
Programowanie internetowe w J2ME
kundę sprawdzał zawartość bufora odebranych danych i wy-
Listing 6. Dodawanie tekstu do formatki mainform
pisywał jego zawartość (w przypadku danych tekstowych do
takich sytuacji nie będzie dochodzić). public void addText(String text)
Znacznie prostszą czynnością jest wysyłanie poleceń. {
W naszym przypadku komendy wysyłać będziemy ze znakiem // Jeśli nie osiągnięto maksymalnej ilości komunikatów,
nowej linii, korzystając z metody println() obiektu strumienia. // dodaj normalnie
Jeśli, Drogi Czytelniku, będziesz chciał dostosować telnet if (number<5)
do swoich wymagań, możesz skorzystać z analogicznej meto- {
dy print()  nie dołącza ona żadnych znaków do przesyłane- messages[number] = text;
go tekstu. Na początku tego artykułu wspominałem o koniecz- labels[number].setText(text+"\n");
ności używania stałej liczby etykiet tekstowych do wyświetla- number+=1;
nia danych. W związku z tym do dodawania poleceń używa- }
my metody addText(), która uwzględnia problemy związane ze else
zmianą wartości etykiet. {
for (int i=0;i<4;i++)
Testowanie // przesuń  w górę etykiety
Kompilacja i uruchamianie programu przebiegają normalnie, messages[i] = new String(messages[i+1]);
jednak w trakcie nawiązywania połączenia wyświetli się ko- // nadaj nową wartość tekstowi, znajdującemu
munikat (Rysunek 2). // się na dole formatki
messages[4] = new String(text);
for (int i=0;i<5;i++)
Listing 5. Klasy służące do odbierania danych
{
class Receiver implements Runnable
// aktualizacja etykiet
{ labels[i].setText(messages[i]+"\n");
public void run() }
{ }
int b = 0; }
buffer = new StringBuffer(); // bufor na dane
try
{ Musimy pamiętać, że korzystanie z Internetu w telefonach
while ((b=in.read())!=-1) // wczytywanie bajtów komórkowych to czynność wymagająca posiadania przez
{ MIDlet specjalnych uprawnień (podobnie jak w przypadku tra-
buffer.append((char)b); dycyjnych apletów w J2SE). Jeśli MIDlet nie posiada upraw-
if ((b==10)||(buffer.length()==256)) nień, w trakcie działania programu zostanie prośba o zaak-
{ ceptowanie lub odrzucenie połączenia.
// kontrola: znak nowego wiersza lub określony rozmiar
// bufora powodują dodanie tekstu i wyczyszczenie Podsumowanie
// bufora Pisanie aplikacji internetowych zawsze wiąże się z pewnym
addText(buffer.toString()); ryzykiem, nie omija ono także programów mobilnych. W przy-
buffer.setLength(0); padku tego rodzaju programów trzeba jednak przede wszyst-
} kim zwrócić uwagę głównie na ograniczenia sprzętowe (ma-
} ła ilość pamięci, brak możliwości nawiązywania połączeń soc-
} ket owych na telefonach z MIDP 1.0). Nie powinno się również
catch (IOException e){} (chociaż jest to teoretycznie możliwe) tworzyć aplikacji-serwe-
} rów na telefony komórkowe; Moc obliczeniowa oraz parame-
} try połączenia internetowego tego typu urządzeń nie stano-
class ScreenPrinter extends TimerTask wią dobrej podstawy do pełnienia funkcji jakiegokolwiek ro-
{ dzaju serwera. Program opisany w niniejszym artykule można
public synchronized void run() rozszerzyć o takie funkcje, jak chociażby zachowywanie więk-
{ szej ilości poleceń, dzięki wykorzystaniu klas ByteArrayInput/
if (buffer.length()>0) OutputStream. Daje to znacznie większe możliwości, aniżeli
{ przechowywanie tekstu bezpośrednio w etykietach.
// jeśli nie mamy do czynienia z tekstami, trzeba Telefony komórkowe mają coraz większe możliwości, choć
// regularnie wypisywać zawartość bufora często nie zdajemy sobie z nich sprawy, a to właśnie od nas,
addText(buffer.toString()); programistów, zależy w jakim stopniu użytkownicy  komórek
buffer.setLength(0); będą mogli korzystać z udostępnionych w nich technologii.
} Strona, z której można pobrać J2ME Wireless Tool-
} kit (najnowsza stabilna wersja  2.2, proces pobrania wy-
} maga uprzedniej rejestracji  http://java.sun.com/j2me/
download.html). n
Software Developer s Journal 7/2006 www.sdjournal.org
57


Wyszukiwarka

Podobne podstrony:
Dostęp do poczty z sieci Internet poprzez program Outlook Express i protokół POP3
2005 01 Pyro i OpenSSL–bezpieczny komunikator internetowy [Programowanie]
Najlepsze programy partnerskie w internecie
7 Internet i programowanie HTML (2)
Internet Marketing Programs
Dostęp do poczty z sieci Internet poprzez program Outlook Express i protokół IMAP4
Program partnerski najszybszym sposobem na zarabianie w internecie
multimedialny kurs tworzenie stron internetowych programu flash
7 34 Programowanie dla Internetu (2)

więcej podobnych podstron