background image

Technologie mobilne

Laboratorium

Zadanie 5 – Mechanizmy zapisu danych na urządzeniu 

przenośnym w JME

background image

Zestawy MIDletów

MIDlety mogą być grupowane w zestawy (MIDlet Suites). W uproszczeniu, zestaw tworzą 
MIDlety umieszczone w jednym pliku .jar i opisane wspólnym deskryptorem JAD. Kolejne wpisy 
w pliku JAD dotyczące MIDletów wchodzących w skład zestawu są umieszczone pod kluczami o 
nazwach : MIDlet-1MIDlet-2 itd. 
Zestawy MIDletów danego urządzenia identyfikujemy korzystając wartości atrybutów MIDlet-
Vendor
 oraz MIDlet-Name z pliku JAD. Te dwie wartości będziemy odtąd określać jako nazwa 
MIDlet Suite
.
Pewnie nie trzeba byłoby o tym na tak wczesnym etapie wspominać, gdyby nie fakt, iż MIDlety 
wchodzące w skład zestawu współdzielą pamięć do zapisywania danych trwałych.

Record Management System 

Record Management System to podstawowy sposób zapisu danych w formie trwałej. Każdy 
MIDlet Suite może stworzyć tzw. Record Stores, czyli „Magazyny Rekordów”, w których będzie 
można przechowywać dane. Record Stores z kolei zawierają Records (rekordy), identyfikowane 
przez liczbowe id (pierwszy rekord ma id równe 1) i zawierające dane w postaci … tablicy 
bajtowej.
Oczywiście, MIDlet Suite może stworzyć wiele magazynów danych. Każdy Record Store posiada 
unikatową nazwę, pozwalającą go zidentyfikować w obrębie zestawu. Możemy również pozwolić 
zewnętrznym zestawom MIDletów na korzystanie z konkretnego magazynu danych.

Główną klasą odpowiedzialną za współpracę z RMS jest klasa RecordStore. Jej metody statyczne 
pozwalają na zarządzanie magazynami rekordów.

public static String[] listRecordStores()

 → zwraca tablicę nazw wszystkich magazynów rekordów dostępnych w ramach zestawu 
MIDletów.

public static void deleteRecordStore(String recordStoreName)

 → pozwala usunąć magazyn rekordów o podanej nazwie (oczywiście oznacza to również usunięcie 
wszystkich rekordów przechowywanych w tymże magazynie)

public static RecordStore openRecordStore(String recordStoreName, boolean 

createIfNecessary, int authmode, boolean writable)

 → otwiera magazyn rekordów, a jeśli nie istnieje, a drugi parametr ma wartość „true”, tworzy 
nowy magazyn rekordów (parametr „authmode” pozwala określić, czy magazyn ma być widoczny 
przez zewnętrzne MIDlet Suites)

public static RecordStore openRecordStore(String recordStoreName, String 

vendorName, String suiteName)

 → otwieranie magazynów rekordów należących do zewnętrznych zestawów MIDletów.

Gdy otworzymy/stworzymy magazyn rekordów, możemy operować na niestatycznych metodach 
klasy RecordStore. Pozwalają one między innymi: 

dodać rekord (addRecord()),

wstawić rekord w konkretne miejsce (setRecord()),

background image

usunąć rekord (deleteRecord()),

pobrać rekord (getRecord()),

zamknąć magazyn rekordów (closeRecordStore()),

ustalić ilość pamięci zajmowanej przez rekordy w magazynie (getSize()),

ustalić ilość wolnej pamięci (getSizeAvailable()),

ustalić rozmiar rekordu (getRecordSize()).

RecordStore umożliwia rejestrowanie obiektów implementujących interfejs RecordListener
Pozwala to nasłuchiwać na zdarzenia dotyczące dodawania, zmiany i usuwania rekordów z danego 
magazynu.

Dodatkowo, mamy dostęp do wyspecjalizowanego iteratora → RecordEnumeration
Pozwala on przechodzić po kolejnych rekordach z danego magazynu.
Już na etapie tworzenia RecordEnumeration możemy zdefiniować podzbiór zbioru rekordów, który 
chcemy przeglądać (użycie RecordFilter) oraz kolejność w jakiej rekordy będą przeglądane (użycie 
RecordComparator). Zainteresowanych tą funkcjonalnością odsyłam do dokumentacji.

W ramach przykładu pokażę dwie metody, które korzystają z opisanego mechanizmu.
Pierwszy z nich to metoda do zapisu ciągu znaków w magazynie danych :

Druga służy do odczytania rekordu o zadanym identyfikatorze z magazynu rekordów :

background image

Komentarze dołączone do powyższych fragmentów kodu tłumaczą, jakie kroki należy podjąć, by 
odczytać lub zapisać dane w magazynie rekordów.

File Connection Optional Package (część dla chętnych)

Pakiet opcjonalny File Connection pozwala operować na plikach istniejących w pamięci 
urządzenia mobilnego. Pakiet ten rozszerza GCF, dodając nowy typ połączenia → FileConnection
Tak więc dostęp do pliku uzyskujemy tworząc połączenie (przypomnienie → korzystamy w tym 
celu z metody open() klasy Connector ). Połączenie to identyfikuje ciąg znaków postaci :

file://<host>/<ścieżka> 

gdzie: 

 

<ścieżka> = <root>/<katalog>/<katalog>/.../<nazwa>

Prawidłowym separatorem dla ścieżek w JME jest „/”, natomiast <root> określa punkt 
„montowania” jednostki pamięci (np. karty pamięci, pamięci telefonu …).
Wszystkie dostępne wartości <root> można ustalić wywołując statyczną metodę klasy 
FileSystemRegistry:

public static java.util.Enumeration listRoots()

Przykładowe wartości, jakie może zwrócić ta metoda :

CFCard,

SDCard,

MemoryStick,

C:,

/.

background image

Przykładowy kod pozwalający otworzyć połączenie z plikiem/katalogiem ma postać :

FileConnection fc = (FileConnection)

                         Connector.open("file:///SDCard/tralala/plik.txt");

Należy podkreślić następujące fakty dotyczące połączenia FileConnection :

1. Połączenie FileConnection może dotyczyć zarówno pliku jak i katalogu. Klasa 

FileConnection posiada metodę isDirectory(), która pozwala sprawdzić, czy zasób jest 
katalogiem, czy też nie.

2. Dobrą praktyką jest, by dla każdego pliku/katalogu tworzyć osobne połączenie.
3. Ścieżka podana jako parametr metody open() nie musi wskazywać na istniejący zasób → 

ważne jest, aby była poprawna! Możemy sprawdzić, czy zasób istnieje ( metoda exists() ), a 
jeśli nie, utworzyć nowy katalog ( mkdir() ) lub plik ( create() ), w miejscu, które definiuje 
ścieżka.

Interfejs FileConnection posiada wiele innych metod, które pozwalają między innymi: 

usunąć plik/katalog ( delete() ),

ustalić rozmiar pliku/katalogu ( fileSize()/directorySize() ),

zmienić nazwę pliku/katalogu ( rename() ),

ustalić, czy plik/katalog można odczytać ( setReadable() / canRead() ) i czy można do niego 
zapisywać ( setWritable() canWrite() ),

pobrać listę elementów zawartych w katalogu ( list() ).

FileConnection, podobnie jak większość połączeń, dziedziczy po InputConnection oraz 
OutputConnection, tak więc zapis do pliku programista realizuje przy wykorzystaniu strumieni, tak 
jak zostało to omówione w poprzednim laboratorium. Podobnie jak każde połączenie, również 
połączenie FileConnection należy zamknąć, korzystając z metody close().

Poniższe przykłady pokazują, jak zapisać ciąg znaków do pliku oraz jak potem te dane odczytać :

background image

Zadania

1. Wyświetl widok typu TextBox, służący do wpisywania tekstu. Dodaj komendy „Wyjdź”, 

„Zapisz” i „Pokaż”. Stwórz magazyn rekordów o wybranej przez siebie nazwie. W ramach 
obsługi komendy „Zapisz” zapisuj w tym magazynie rekordy zawierające tekst wpisany w 
TextBox'ie.

2. Stwórz widok typu List, wyświetlany po wybraniu komendy „Pokaż”. Niech lista wyświetla 

wszystkie rekordy dodane do tej pory. Dodaj komendę powrót, umożliwiającą powrót do 
widoku z TextBox'em. 

3. Dodaj do listy komendę usuń, która spowoduje usunięcie rekordu, który jest aktualnie 

wybrany w ramach listy (Uwaga : lista ma elementy numerowane od 0, rekordy są 
numerowane od 1).

4. (dla chętnych) Stwórz drugi MIDlet. Spraw, aby mógł pracować na tym samym magazynie 

rekordów, co pierwszy. Zaimplementuj zapisywanie zawartości magazynu rekordów do 
pliku oraz odczyt tej zawartości z pliku.