z wykorzystaniem języka Java ME ćwiczenia 3 Wykorzystanie klasy List do tworzenie menu Klasa List - tworzenie list wyboru (EXCLUSIVE, MULTIPLE, IMPLICIT) Dodatkowe możliwości (dodatkowe komendy, pliki graficzne itp.) Przykładowa aplikacja import javax.microedition.midlet.midlet; import javax.microedition.lcdui.*; import java.io.*; public class MenuLista extends MIDlet implements CommandListener { private Display dp; // wykorzystanie klasy List (3 listy: menu główne + listy wyboru) private List mainmenu, samochodylista, plytylista; // wykorzystanie klasy Form (formularz w ustawieniach) private Form formularz; // wykorzystanie klasy TextField (pole tekstowe w formularzu) private TextField tf; 1
// wykorzystanie klasy Alert (informacje o programie) private Alert info; // wykorzystanie klasy Command (polecenie OK na ekranach) private Command okcommand; // wykorzystanie klasy Image (obrazki w menu głównym i na listach); private Image samochod, plyta, konfiguracja, informacja, wyjscie; public MenuLista() { // utworzenie menu głównego aplikacji (wykorzystanie listy typu IMPLICIT) mainmenu = new List("Menu aplikacji", List.IMPLICIT); // utworzenie obrazków z plików znajdujących się w katalogu res samochod = Image.createImage("/car.png"); plyta = Image.createImage("/cd.png"); konfiguracja = Image.createImage("/settings.png"); informacja = Image.createImage("/info.png"); wyjscie = Image.createImage("/exit.png"); catch (IOException e) { System.out.println("Brak obrazka!"); // dodanie kolejnych pozycji menu (drugi parametr obiekt klasy Image) mainmenu.append("samochody", samochod); mainmenu.append("płyty CD", plyta); mainmenu.append("konfiguracja", konfiguracja); mainmenu.append("informacja o programie", informacja); mainmenu.append("wyjście", wyjscie); // ustawienie nasłuchiwacza (bieżąca klasa) mainmenu.setcommandlistener(this); // utworzenie polecenia OK okcommand = new Command("OK", Command.OK, 0); // utworzenie listy samochodów (wykorzystanie listy typu EXCLUSIVE) i dodanie // pozycji samochodylista = new List("Wybierz samochód", List.EXCLUSIVE); samochodylista.append("fiat Panda", samochod); samochodylista.append("ford Mondeo", samochod); samochodylista.append("seat Leon", samochod); samochodylista.append("skoda Fabia", samochod); // dodanie do listy samochodów polecenia OK samochodylista.addcommand(okcommand); // ustawienie nasłuchiwacza (bieżąca klasa) samochodylista.setcommandlistener(this); // utworzenie listy płyt CD (wykorzystanie listy typu MULTIPLE) i dodanie pozycji plytylista = new List("Zaznacz płyty", List.MULTIPLE); plytylista.append("dire Straits - Brothers in Arms", plyta); plytylista.append("pink Floyd - Dark Side of The Moon", plyta); plytylista.append("guns n' Roses - Use your Illusion", plyta); plytylista.append("queen - Innuendo", plyta); plytylista.append("led Zeppelin - IV", plyta); // dodanie do listy płyt CD polecenia OK 2
plytylista.addcommand(okcommand); // ustawienie nasłuchiwacza (bieżąca klasa) plytylista.setcommandlistener(this); // utworzenie formularza formularz = new Form("Konfiguracja"); // utworzenie pola tekstowego tf = new TextField("Załóż hasło", null, 20, TextField.ANY); // dodanie pola tekstowego formularz.append(tf); // dodanie do formularza polecenia OK formularz.addcommand(okcommand); // ustawienie nasłuchiwacza (bieżąca klasa) formularz.setcommandlistener(this); // pobranie referencji do obiektu Display dp = Display.getDisplay(this); public void startapp() { // ustawienie ekranu głównego (menu główne) dp.setcurrent(mainmenu); public void pauseapp() { public void destroyapp(boolean unconditional) { public void commandaction(command c, Displayable d) { // sprawdzenie czy wystąpiło polecenie wyboru z listy i jesteśmy w głównym menu if (c == List.SELECT_COMMAND && d == mainmenu) { // pobranie indeksu wybranej pozycji int indeks = mainmenu.getselectedindex(); // pobranie tekstu związanego z wybraną pozycją String akcja = mainmenu.getstring(indeks); // obsługa pozycji menu (sprawdzanie akcji ze Stringiem) if (akcja.equals("wyjście")) { // zakończenie pracy midletu destroyapp(true); notifydestroyed(); else if (akcja.equals("samochody")) { // ustawienie głównego ekranu na listę samochodów dp.setcurrent(samochodylista); else if (akcja.equals("płyty CD")) { // ustawienie głównego ekranu na listę płyt CD dp.setcurrent(plytylista); else if (akcja.equals("konfiguracja")) { // ustawienie głównego ekranu na formularz dp.setcurrent(formularz); else if (akcja.equals("informacja o programie")) { 3
// utworzenie obiektu klasy Alert Alert al = new Alert("Informacje","Autor: Jan Kowalski\nWersja: 0.666alfa\n", informacja, AlertType.INFO); // czas na jaki ma się wyświetlić okno alertu (milisekundy) al.settimeout(3000); // ustawienie głównego ekranu na nasz alert, a po upływie czasu na menu // główne dp.setcurrent(al, mainmenu); // obsługa polecenia OK (powrót do menu głównego) else if (c == okcommand) { dp.setcurrent(mainmenu); Zapis danych w pamięci urządzeń mobilnych Wykorzystanie RMS (Record Management System) o pakiet javax.microedition.rms o klasa RecordStore (zarządzanie zbiorami i rekordami) utworzenie obiektu klasy RecordStore RecordStore rs = RecordStore.openRecordStore("baza", true); operacje na zbiorze (dodawanie rekordów, modyfikacja, usuwanie) zamknięcie otwartego zbioru rs.closerecordstore(); Przykładowa aplikacja Zadaniem aplikacji ma być tworzenie i przechowywanie notatek tekstowych. import javax.microedition.midlet.midlet; import javax.microedition.lcdui.*; import javax.microedition.rms.*; import java.io.*; public class Kajet extends MIDlet implements CommandListener { // wykorzystanie klasy Display private Display dp; // wykorzystanie klasy List (menu główne, menu z notatkami) private List mainmenu, listanotek; // wykorzystanie klasy TextBox (dodawanie i wyświetlanie notatek) private TextBox tb, tbf; // wykorzystujemy klasę RecordStore do zapisu danych w pamięci urządzenia private RecordStore rs; // wykorzystanie klasy Command (polecenie powrotu i zapisywania) 4
private Command backcommand, savecommand, backlistcommand; // tablica przechowująca notki String[] notki; // konstruktor public Kajet() { // otwieramy zbiór z rekordami (jeśli nie istnieje zostanie utworzony) rs = RecordStore.openRecordStore("Notatki", true); catch (RecordStoreException e) { System.out.println ("Problem z RMS"); mainmenu = new List("Kajet", List.IMPLICIT); mainmenu.append("nowa notka", null); mainmenu.append("lista notek", null); mainmenu.append("wyjście",null); mainmenu.setcommandlistener(this); backcommand = new Command("Wróć", Command.BACK, 0); backlistcommand = new Command("Wróć", Command.BACK, 0); savecommand = new Command("Dodaj", Command.SCREEN, 1); tb = new TextBox("Nowy wpis", null, 320, TextField.ANY); tb.addcommand(backcommand); tb.addcommand(savecommand); tb.setcommandlistener(this); dp = Display.getDisplay(this); public void startapp() { dp.setcurrent(mainmenu); public void pauseapp() { public void destroyapp(boolean unconditional) { // zamknięcie zbioru z danymi rs.closerecordstore(); catch (RecordStoreException e) { System.out.println ("Nie można zamknąć RMS"); 5
public void commandaction(command c, Displayable d) { // sprawdzenie czy wystąpiło polecenie wyboru z listy i jesteśmy w głównym menu if (c == List.SELECT_COMMAND && d == mainmenu) { // pobranie indeksu wybranej pozycji int indeks = mainmenu.getselectedindex(); // pobranie tekstu związanego z wybraną pozycją String akcja = mainmenu.getstring(indeks); // obsługa pozycji menu (sprawdzanie akcji ze Stringiem) if (akcja.equals("wyjście")) { // zakończenie pracy midletu destroyapp(true); notifydestroyed(); else if (akcja.equals("nowa notka")) { // wyczyszczenie zawartości pola tekstowego tb.setstring(null); // ustawienie głównego ekranu na nowy wpis dp.setcurrent(tb); else if (akcja.equals("lista notek")) { // utworzenie listy notek listanotek = new List("Lista notek", List.IMPLICIT); // wyliczenie wszystkich rekordów RecordEnumeration re = rs.enumeraterecords(null, null, false); // zmienna pomocnicza int i = 0; // tworzymy tablicę Stringów z notkami o rozmiarze takim jak // liczba rekordów notki = new String[re.numRecords()]; // przechodzimy przez wszystkie rekordy w naszym zbiorze while(re.hasnextelement()){ // odczytujemy rekord byte[] record = re.nextrecord(); // tworzymy strumien danych wejściowych ByteArrayInputStream raw = new ByteArrayInputStream(record); DataInputStream in = new DataInputStream(raw); // odczytujemy notkę String notka = in.readutf(); // wpisujemy notkę do tablicy notki[i] = notka; i++; // tworzymy krótką wersję notki do pokazania na liście notka = notka.substring(0, (notka.length()) > 40? 40 : notka.length()) + "..."; listanotek.append(notka, null); 6
// zamykamy strumień danych wejściowych in.close(); catch (IOException e) { System.out.println ("Bład wejścia/wyjścia"); catch (RecordStoreException e) { System.out.println ("Błąd zapisu RMS"); // dodajemy polecenie powrotu do głównego menu listanotek.addcommand(backcommand); // ustawiamy nasłuchiwacza na bieżącą klasę listanotek.setcommandlistener(this); // ustawienie głównego ekranu na listę notek dp.setcurrent(listanotek); // obsługa listy notek, po wybraniu notki pokazujemy jej całą treść else if (c == List.SELECT_COMMAND && d == listanotek) { // tworzymy pole tekstowe z zawartością odpowiedniej notki pobranej z tablicy // notek tbf = new TextBox("Pełny tekst", notki[listanotek.getselectedindex()], 320, TextField.UNEDITABLE); // dodajemy polecenie powrotu na listę notek tbf.addcommand(backlistcommand); // ustawiamy nasłuchiwacz tbf.setcommandlistener(this); // ustawiamy bieżący ekran na nasze pole z pełną treścią notki dp.setcurrent(tbf); // obsługa polecenia BACK (powrót do menu głównego) else if (c == backcommand) { dp.setcurrent(mainmenu); // obsługa polecenia BACK (powrót do menu z listą notek) else if (c == backlistcommand) { dp.setcurrent(listanotek); // obsługa polecenia zapisz else if (c == savecommand) { // tworzymy strumień danych wyjściowych ByteArrayOutputStream arraystream = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(arrayStream); // wpisujemy dane pobrane z pola tekstowego do strumienia out.writeutf(tb.getstring()); // tworzymy tablice bajtów byte[] data = arraystream.tobytearray(); // dodajemy rekord rs.addrecord(data, 0, data.length); 7
// zamykamy strumień out.close(); catch (IOException e) { System.out.println ("Bład wejścia/wyjścia"); catch (RecordStoreException e) { System.out.println ("Błąd zapisu RMS"); // ustawiamy bieżący ekran na główne menu dp.setcurrent(mainmenu); Połączenie z internetem Wszystkie aplikacje mobilne umożliwiają obsługę połączeń sieciowych za pomocą prostego API będącego składową GFC (Generic Connection Framework). Obsługiwane protokoły to http oraz https. Pakiet javax.microedition.io zawiera większość klas związanych z GFC. Nawiązanie połączenia to wykorzystanie jednej z metod open dostępnych w klasie Connector. Dostęp do danych z sieci jest możliwy w następujący sposób: String url = "http://strona.pl/index.html"; HttpConnection c = (HttpConnection) Connector.open(url); InputStream in = c.openinputstream(); // in.read()...odczyt danych 8
Przykładowa aplikacja (pobieranie kursu USD z witryny NBP) import javax.microedition.lcdui.*; import javax.microedition.midlet.midlet; import javax.microedition.io.*; import java.io.*; public class PobieranieDanych extends MIDlet implements CommandListener { // wykorzystanie klasy TextBox (okno tekstowe) private TextBox tb; // wykorzystanie klasy Command (obsługa komend) private Command exitcommand; // wykorzystanie klas HttpConnection (połączenie po http) oraz InputStream (obsługa // strumienia wejściowego) private HttpConnection c; private InputStream is; // wykorzystanie klasy StringBuffer (dynamiczny łańcuch tekstowy) private StringBuffer sb; public PobieranieDanych () { // tworzymy obiekt klasy StringBuffer sb = new StringBuffer(); // łączymy się ze stroną NBP c = (HttpConnection) Connector.open("http://nbp.pl/Kursy/KursyA.html", Connector.READ, true); // otwieramy strumień danych wejściowych is = c.openinputstream(); int ch=0; // odczytujemy wszystkie dane (-1 koniec danych) oraz dodajemy je do // łańcucha tekstowego while ((ch = is.read())!= -1) { sb.append((char) ch); catch (IOException x){ System.out.println ("Błąd wejścia wyjścia"); finally { is.close(); c.close(); catch (IOException x) { System.out.println ("Błąd wejścia wyjścia"); 9
// zamieniamy obiekt klasy StringBuffer na String (potrzebujemy kilku metod) String wyn = sb.tostring(); // wyszukujemy ciągu znaków USD int i = wyn.indexof("usd"); // szukamy aktualnegoo kursu USD i = i + 26; // wycinamy kurs (ciągle będzie to łańcuch tekstowy) String wartosc = wyn.substring(i, i + 6); // zamieniamy, na. wartosc = wartosc.replace(',','.'); // konwertujemy String z kursem na zmienną typu float float kurs = Float.parseFloat(wartosc); // tworzymy nowy obiekt klasy TextBox wraz z aktualnym kursem tb = new TextBox("Aktualny kurs USD", "USD: " + kurs, 100, TextField.ANY); // tworzymy nowe polecenie exitcommand = new Command("Zakończ", Command.EXIT, 0); // dodajemy polecenie do pola tekstowego tb.addcommand(exitcommand); // wskazujemy obiekt obslugujacy zdarzenia tb.setcommandlistener(this); public void startapp() { // ustawiamy ekran poczatkowy Display.getDisplay(this).setCurrent(tb); public void pauseapp() { public void destroyapp(boolean u) { // ciało metody z interfejsu CommandListener public void commandaction(command c, Displayable d) { Wysyłanie tekstu // obsluga polecenia exitcommand (kończymy działanie aplikacji) if (c == exitcommand) { destroyapp(true); notifydestroyed(); Java ME udostępnia prostą komunikację tekstową i multimedialną za pomocą Wireless Messaging API (WMA). WMA bazuje na GFC (Generic Connection Framework). Pakiet javax.wireless.messaging zawiera większość klas i metod potrzebnych do takiej 10
komunikacji. Wysłanie bądź też odebranie połączenia to utworzenie obiektu klasy MessageConnection oraz wypełnienie treści wiadomości i jej wysłanie. Poniżej prosty przykład wysyłania wiadomości tekstowej (SMS): import javax.microedition.lcdui.*; import javax.microedition.midlet.midlet; import javax.microedition.io.*; import java.io.*; import javax.wireless.messaging.*; /** * MIDlet: WysylanieSMS * Klasy główne: TextBox, Alert (dziedziczące z klasy Screen) */ public class WysylanieSMS extends MIDlet implements CommandListener, Runnable { // wykorzystanie klasy TextBox (okno tekstowe) private TextBox tb; // wykorzystanie klasy Command (obsługa komend) private Command exitcommand, sendcommand; // wykorzystanie klasy Display private Display dp; public WysylanieSMS() { tb = new TextBox("Wpisz tekst", null, 160, TextField.ANY); // tworzymy nowe polecenia (polecenia związane z aplikacją mają typ // Command.SCREEN) exitcommand = new Command("Zakończ", Command.EXIT, 0); sendcommand = new Command("Wyślij SMS", Command.SCREEN, 1); // dodajemy polecenia do pola tekstowego tb.addcommand(exitcommand); tb.addcommand(sendcommand); // wskazujemy obiekt obslugujacy zdarzenia tb.setcommandlistener(this); dp = Display.getDisplay(this); public void startapp() { dp.setcurrent(tb); public void pauseapp() { public void destroyapp(boolean u) { // ciało metody z interfejsu CommandListener public void commandaction(command c, Displayable d) { // obsluga polecenia exitcommand (kończymy działanie aplikacji) if (c == exitcommand) { destroyapp(true); notifydestroyed(); 11
// obsluga polecenia infocommand (wyświetlenie informacji użytkownikowi) if (c == sendcommand) { // tworzymy nowy wątek Thread t = new Thread(this); // startujemy wątek t.start(); // tworzymy obiekt klasy Alert wraz z odpowiednimi danymi Alert al = new Alert("Informacja", "Wysłałeś SMS", null, AlertType.INFO); // ustawiamy czas (podany w ms) przez jaki Alert ma być // wyświetlany al.settimeout(2000); // wyświetlamy Alert oraz wskazujemy na ekran, który ma zostać // wyświetlony po zamknięciu Alerta dp.setcurrent(al, tb); public void run() { MessageConnection mc = null; // Inbox telefonu komórkowego nie podajemy portu String cs = "sms://+5550001"; // tworzymy połączenie mc = (MessageConnection) Connector.open(cs); // tworzymy nową wiadomość tekstową TextMessage tm = (TextMessage) mc.newmessage(messageconnection.text_message); // ustawiamy treść wiadomości tm.setpayloadtext(tb.getstring()); // wysyłamy mc.send(tm); catch (IOException ioe) { System.out.println ("Bład wejścia/wyjścia"); // sprawdzamy czy połączenie zostało otwarte if (mc!= null) { // zamykamy połaczenie mc.close(); catch (IOException ioe) { System.out.println ("Błąd wejścia/wyjścia"); 12
Zadania 1. Uruchom MIDlet z listą jako menu. Zmień pliki graficzne, dodaj nowe pozycje w poszczególnych listach. 2. Zapoznaj się z działaniem MIDletu Kajet. Dodaj ikony do poszczególnych pozycji menu. Zastanów się jak rozbudować funkcjonalność aplikacji (usuwanie notek, aktualizacja). Wprowadź modyfikacje. 3. Uzupełnij MIDlet PobieranieDanych o nowe waluty (EUR, GPB itd.). Zastanów się jak przechowywać dane w pamięci urządzenia. Zaprojektuj MIDlet przechowujący kursy kilku walut wraz z ich datami. 4. Napisz aplikację umożliwiającą wysyłanie SMS'ów, ich archiwizację (folder wysłane). Program ma mieć możliwość tworzenia SMS'ów przeznaczonych do wysłania później (folder wersje robocze/do wysłania). 13