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