Zum Inhalt springen

Projekt:Mobile GIS

Aus Wikiversity


Einordnung

[Bearbeiten]

Das Projekt ist ein Teilprojekt meines Wikiversity-Forschungsprojektes IT-Nomaden aus dem IZ Science, Technology and Sociology. Darin wird es gebraucht um eine Humangeographie zu machen.

Zunächst geht es darum eine Modellarchitektur zu machen, um eine Geogrid mit einer Community Application zu verbinden. Beides erst wird uns ermöglichen das überhaupt evolutionäre Entwicklungen eines Sozialsystems sichtbar zu machen. Sonst werden wir immer von den Datenmengen erschlagen.

Die Fuzzy-Architektur der Benutzerdatenbank hat seinen Grund darin, dass damit eigentlich raumsensitive sozialwissenschaftliche Forschung gemacht werden soll, das funktioniert eben nicht mit einer Wahr/Falsch Logik.

Die P2P Technik soll an die universitären Versuche anschließen, die das Kartenmaterial veröffentlichen wollen. Bis dahin werden die Karten wahrscheinlich nur durch teures Geld und durch den Besitz einer größeren Serverfarm verwendbar. Also eher etwas für reiche Organisationen.

Vorkenntnisse

[Bearbeiten]

Die Mitarbeiter sollten gewisse Vorkenntnisse haben, um den Prototyp mitgestalten zu können. Die Hauptsprache wird Java sein.

Kenntnisse:

  • Datenbank-Kenntnisse
  • P2P Filesharing/Computing
  • Skriptsprache
  • Java (C++)
  • SQL

Mitarbeiter

[Bearbeiten]
  • astroboi

plutokid@gmx.de

Offene Fragen

[Bearbeiten]
  • Implementation von Layern
  • Keine Authentifizierung von Usern

Mobile Geogrid

[Bearbeiten]
  • Indirekte Unterstützung von KMRG-Karten (Kartenserver transformiert KMRG-Format ins PNG-Format)
  • Funktionalität der mobilen Geogrid-Version (Name, Maßstab, Projektion, usw.)
  • Herunterladen von PNG-Kacheln, die zusammen einen Kartenausschnitt bilden
  • Darstellen der Kartenausschnitte im Vollbildmodus
  • Weiches Scrolling des Kartenausschnittes
  • Nachladen des Kartenausschnittes
  • Darstellung des Längen- und Breitengrades der anvisierten Position auf dem Kartenausschnitt
  • Positionsbestimmung über einen Bluetooth-GPS-Empfänger, der das NMEA-Protokoll unterstützt
  • Zentrieren der Karte auf die empfangenen Koordinaten des GPS Empfängers
  • Setzen von Referenzpunkten
  • Cachen von bereits geladenen Karteninformationen und PNG-Kacheln
  • Menüstruktur mit Optionseinstellungen

Folgende Kriterien sollen noch erfüllt werden

  • Unterstützung von mindestens einem der Overlayformate (Binär, ASCII, XML)
  • Herunterladen von Overlays
  • Direkte Speicherung von Karten auf dem Gerät
  • Zoomen von Karten
  • Unterstützung von Höhendaten
  • Positonsbestimmung über Location API
  • Unterstützung von MAPS Karten

Mindestanforderungen an das mobile Gerät

[Bearbeiten]
  • CLDC 1.1/MIDP 2.0
  • 512 KB RAM
  • 111 KB Speicherplatz für .jar-Datei
  • 128 KB Record Management System

Testgeräte

[Bearbeiten]
  • Sony Ericson K700i
  • Siemens S65
  • Nokia 6230
  • DEll Axim PockettPC

Code Recycling aus JavaMap

[Bearbeiten]
  • KMRG-Format kann nicht eingesetzt werden
  • AWT- und Swingkomponenten können nicht eingesetzt werden
  • Projektionsklassen mit Methoden aus der java.lang.Math Klasse können nicht eingesetzt werden

Architekturüberschicht

[Bearbeiten]

3-Schichten Architektur

Modellschicht

[Bearbeiten]
  • Abstrahieren und Implementieren der Karte
  • Projektionen
  • GPS Empfang
  • Zugriffskomponenten auf die Datenquelle
  • Cachen der empfangenen Daten

Controllerschicht

[Bearbeiten]
  • Zentrale Controller-Instanz
  • Actionsklassen mit Action-Threads
  • Initialisierungen werden in Plug-ins ausgelagert

Viewschicht

[Bearbeiten]
  • Menüdarstellung mit mehreren High-Level-LCDUI Komponenten
  • Kartendarstellung mit Low-Level-LCDUI Komponenten (darunter Layerkomponenten)


View High-Level-LCDUI Komponenten Low-Level-LCDUI Komponenten
Controller Conroller Instanz Aktionen Initialisierungs-Plug-ins
Model Karte Projektion GPS Datenquelle Cache

Modellschicht

[Bearbeiten]

Datenquelle

[Bearbeiten]

Die Kartendaten holt sich der Prototyp nur über den Kartenserver. Die Implementierung wird vom technischen Datenzugriff abstrahiert, indem ein Interface IMapDataProvider spezifiziert wird, das Interface definiert Operationen zum Zugriff auf Kartendaten. Der Klient eines IMapDataProvider fordert die Kartendaten in Nachrichtenform an. Das IMapDataProvider Interface wird bisher nur auf das HTTP-Protokoll spezifiziert mit HTTPMapDataProvider. Ein Dummy DummyLocalMapDataProvider sendet immer gleiche Testnachrichten.

Kartenformat

[Bearbeiten]

Das Kartenformat ist PNG, dass wior mit dem Low-Level API zeichnen. PNGs können nativ vom mobilen Gerät dekomprimiert und dargestellt werden. Aus einer PNG Datei kann ein Image Objekt erzeugt werden, das über drawImage() Methode auf dem Bildschirm gezeichnet wird.

Falls das Wireless Toolkit 2.2 verwendet wird ist am besten, aber das muss nicht sein. LazyTile

Kachelung der Karte

[Bearbeiten]

Der Server generiert zuerst einen Kartenausschnitt und erzeugt anschließend PNG-Kacheln. Mit der Kachelung können wir eine flexible Nachladestrategie machen, weil nur die benötigte Kacheln nachgeladen werden müssen. Bereits geladene Kacheln können in dem neuen Kartenausschnitt wiederverwendet werden. Der überlappende Teil vom alten und dem neuen Karten wird vom alten Kartenabschnitt auf den neuen Kartenabschnitt kopiert.

Eine Kachel wird durch das Interface ITile repräsentiert, das den lesenden Zugriff auf Breite, Höhe, Zoofaktor, Positionsangabe (PixelCoordinate der linken oberen Ecke) und auf das eigentliche Image Objekt bietet. Die Kacheln haben zwei Zustände initialisiert und nicht-initialisiert. Die Initialisierung der Zustände übernimmt das abgeleitete Interface von ITile ILazyTile. Es gibt hier nur eine konkrete Implementierung des ILazyTile Interface, nämlich die Klasse SquareTile Klasse. CLDC/MIDP kann nicht serialisieren, deswegen diese Konstruktion. Aus einem Image-Objekt läßt sich nicht mehr das originale Bytefeld erzeugen, das für das Cachen benötogt wird. Erst wenn die Kachel gecached wurde, wird die Cachel initialisiert und kann gezeichnet werden. Falls man eine nicht-initialisierte Kachel aufruft wird eine IllegalStateException geworfen. Der Server empfängt die Kacheln in einem Bytestrom, in dem die PNG mit absoluten Positionsangaben (in Form einer serialisierten PixelCoordinate) zusammengefaßt werden. Teure HTTP-Connections werden billiger, weil mehrere Kacheln in einem Bytestrom zusammengefaßt werden. Die Interpretation des Bytestroms macht die PackedTilesMessageCLDC Klasse mit der Implementation IPackedTilesMessageCLDC Interface.

Sektionskonzept

[Bearbeiten]

Die Handys können keine komplette Karte im Speicher halten, deswegen verwenden wir Sektionen. Eine Sektion sollte mindestens die Display-Größe abdecken. Die Karte und die Sektion repräsentieren wir wieder durch Interfaces: IMap und ISection.

Ein IMap Objekt enthält die Karteninformation wie Breite, Höhe, Maßstab und Projektion in Form eines aggregierten IProjection Objekt. Identifiziert werden diese Objekte durch eindeutige IMapIdentifier Objekt, das sich aus der MapID, dem Kartennamen und der URL des Kartenservers zusammensetzt, damit ist die Karte eindeutig gekennzeichnet. Das IMapIdentifier Objekt ist auch gleichzeitig das Schlüsselobjekt zu Hashtables, deswegen muss sie das vom Objekt Klasse geerbten Methoden hashCode und equals korrekt überschreiben.

Besser ist es eigentlich die Karten über einen Hashcode zu identifizieren statt über einen Kartennamen, aber hier geht es um rapid prototyping, damit man rasch Geschwindigkeitstest durchführen kann.

Die Implementierung des IMAp Interfaces ist MapCLDC.

Eine Sektion wird durch ein ISection Objekt abstrahiert und enthält mehrere ITile Objekte (Repräsentation einer Kachel). Jede Sektion kennt ihre Karte, d.h. das ISection Objekt hat eine Referenz auf ein IMap Objekt. Die Sektionen legen wir als quadratisch fest, die einzige Implementation der ISection Interface ist deswegen SectionQuare.

Die Codes der Konstruktion und der Repräsentation sollen voneinander isoliert werden, um den Konstruktionsprozeß der Objekte besser kontrollieren zu können. Das übernehmen sogenannte "Erbauerobjekte" für die IMap und ISection Objekte. "Erbauerobjekte" sind Entwurfsmuster und werden selber wieder durch "Fabriken" erzeugt.

Erzeugung von Sektionen

[Bearbeiten]

Die Kommunikation von Klassen ist zu abstrahieren über Interfaces, damit die Implementierung flexibel wird.

Erbauer für ISection Objekte implementieren das ISectionBuilder Interface. Das Interface erzeugt und lädt die Sektionen nach. Die SectionBuilderSquare Klasse implementiert das Interface und ist der Erzeuger für die SectionSquare Objekte. Das SectionBuilderSquare Objekt hat keine Referenz auf die erzeugten oder nachgeladenen Sektionen. Umgekehrt kennt aber jedes erzeugte SectionSquare Objekt seinen Erbauer unter dem ISectionBuilder Interface fürs Nachladen. Die nachzuladenen Kacheln teilt das IReloadStrategy mit, dass vom SectionBuilderSquare Objekt aufgerufen wird.

Eine Sektion hat ein Zentrum repräsentiert durch die PixelCoordinate, sie wird an das SectionBuilderSquare Objekt mitgeteilt, um die Sektion zu erzeugen. Diese Koordinate ist der Referenzpunkt für die linken, oberen Ecken der zu ladenen Kacheln. Eine Sektion wird nachgeladen, indem die zu ladenen Kacheln ausgetauscht werden. Konsistente Sektionen haben nach dem Nachladen dieselbe Anzahl Kacheln wie die alte Sektion. Die rausgefallenen Kacheln gehen in die Garbage Collection.

Nachladestrategie

[Bearbeiten]

Wenn der sichtbare Bildausschnitt an die Sektionsgrenze kommt, it nachzuladen. Der Sektionsmittelpunkt wird durch den Bildausschnittzentrum neu festgelegt. Der neue Sektionsmittelpunkt wird ausgehend vom Bildausschnittszentrum in die linke, obere Ecke einer zentralen Kachel verlegt. Das funktioniert gut, solange die Kacheln nicht zu groß werden. Die Bewegungsrichtung des Bildauschnittes bleibt unberücksichtigt.

Kommunikation mit dem Kartenserver

[Bearbeiten]

Gepuffertes Lesen ist schneller als das Einlesen jedes einzelnen Bytes. Mit den Kacheln läuft das leider nicht, weil sie zu groß sind.

Die Kommunikation mit dem Kartenserver ist gekapselt durch die abgeleitete Klasse HTTPMapDataProvider aus der IMapDataProvider Interface. Die Anfragemethoden erzeugen aus den übergebenen Parametern eine URL und öffnen über eine Connector Klasse des Generic Connection Frameworks eine HTTPConnection. Nach dem Überprüfen des HTTP-Statuscodes wird ein DataInputStream geöffnet, den den Bytestrom vom Server repräsentiert. Die empfangenen Bytes werden zunächst in einem Bytefeld gepuffert, aus dem später die Nachrichtenobjekte erzeugt werden. Aus dem DataInputStream wird das Nachrichtenobjekt erzeugt (PackedTilesMessageCLDC).

1. Als Klient tritt ein MapBuilder auf, der die getPackedTilesMessage Methode aufruft. ER übergibt die absolute Position aller Kacheln.

2. Die übergebenen Parameter werden zu einer URL-String zusammengeführt. Eine statische Methode der Connector Klasse eröffnet zu dieser URL eine HTTPConnection.

3. Der DataInputStream der HTTPConnection wird geholt.

4. Der Konstruktor der PackedTilesMessageCLDC bekommt den DataInputStream übergeben und initialisiert die PackedTilesMessageCLDC Instanz mit den DataInputStream enthaltenen Daten.

5. Die HTTPConnection wird nach dem Erzeugen der Nachricht wieder geschlossen.

6. Der HTTPMapDataProvider gibt die erzeugte Nachricht zurück.

Authentifizierung mit Username und Passwort gibt es beim Prototypen nicht, damit jeder Zugriff auf die Kartendaten hat.

Die Kommunikation kann vom Anwender abgebrochen werden, weil sie in einem separaten Thread läuft. Dazu schließt man einfach die HTTPConnection durch einen anderen Thread. Die Referenz auf die HttpConnection ist zu kennzeichnen mit dem Java SChlüsselwort voltile. Jede Variable hat dann den aktuellen Wert im Thread, sonst arbeiten die Threads mit einer veralteten Kopie der Variable.

Caching der geladenen Karten und Kacheln

[Bearbeiten]

Cachen ist notwendig, weil die Verbindungen zum Kartenserver lahm sind. Macht das RecordStore Management System (RMS). Definiert werden zwei Caches, Daten werden in zwei Record Stores abgelegt.

Cache RecordStore Interface
Map Cache RECORDSTORE_MAP IMapCache
Tile Cache RECORDSTORE_TILE_HEADER ITileCache
- RECORDSTORE_TILE_IMAGE -

Map Cache

[Bearbeiten]

In diesem Cache sind die Nachrichten aufbewahrt, um eine MapCLDC Instanz zu erzeugen. Die Nachrichten werden in einem Bauplan zusammengepackt und im RecordStore MAP abgelegt. Die gecachte Karte identifiziert sich mit einem MapIdentifier Objekt. Die Länge des Bytestroms wird vor jedem erialisierten Objekt gestellt, damit der Bytestrom korrekt ausgelesen wird. Die SerialVersion der Nachrichten zusammen mit dem MapIdentifier zeigen an, ob man mit der Implementierung das Ganze deserialisieren kann.

MapIdentifier MapInfoMessage MapBoundingMessage ProjectionParameterMessage

Über das Interface IMapCache kann auf das Map Cache zugegriffen werden. Implementiert wird es mit MapCacheRMS. Eine Referenz steht bei dem MapBuilder. Der Cache ist nicht limitiert.

Die Kacheln werden mit einem eigenen Cache dem Tile Cache, der drei RecordStores verwendet:

  • TILE_HEADER
  • TILE_IMAGE
  • TILE_CONFIGURATION

Die Header und die Bilder sind getrennt um schneller nach den richtigen Kacheln suchen zu können. In den RAM Speicher kommen die Header nach dem Start. Die Änderungen in den Headern sind nur im RAM nachvollzogen, die Bilder stehen nicht im RAM, Änderungen bei den Bildern werden sofort im TILE_IMAGE nachvollzogen.

Metainformation der Kacheln wie Position, MapIdentifier, Zoomfaktor, Bildgröße sind aufbewahrt im RecordStore TILE_HEADER. Ein Eintrag darin verweist auf einen Record Eintrag im TILE_IMAGE. Die ältesten Kacheln werden mit dem Clock-Index (ID der "ältesten" Kacheln) gefunden und steht in der TILE_CONFIGURATION. Denn nur die ältesten Kacheln sollen der Garbage Collection übergeben werden.

Eine nachzuladene Kachel wird über dem Second-Chance Algorithmus bestimmt, eigentlich einfach ein modifizierter FIFO. Die acheln werden in einem Ringspeicher abgelegt, ein routierender Clock-Index ist der Marker fürs Einfügen. Eine Position ohne Second-Chance Flag wird als auszutauschende Kachel erkannt. Ist ein Second-Chance Flag vorhanden wird diese Position übersprungen und der Flag entfernt. Eine Kachel erhält einen Flag, wenn auf sie zugegriffen wurde.

Positionsbestimmung

[Bearbeiten]

Die Klasse BluetoothGPS Receiver verbindet mit dem GPS Emfänger. Intern ist es die private, verschachtelte Klasse namens GPSReceiver, eine Kindklasse von java.util.TimerTask. Der Kontakt wird in Sekundentakten hergestellt mit dem Klient hergestellt, der ihn mit den Methoden start und stop mit den übergebenen Parametern in ms steuert. Der GPS-Empfang startet eine Instanz der Klasse GPSReceiver mit einem Objekt des java.util.Timer. Die Threads sind gekapselt, denn TimerTask ist nicht wiederverwendbar. Jeder GPS-Datenverkehr startet mit einem neuen Objekt TimerTask. Der Klient wird benachrichtigt beim geglückten GPS-Empfang, wenn er sich als Observer bei der Klasse BluetoothGPSReceiver anmeldet. Die Bluetoothadresse instanziert eine Instanz der Klasse BluetoothGPSReceiver. Das Programm arbeitet nun vier SChritte ab.

  1. Anmeldung eines IGPSObserver
  2. BluetoothReceiver Instanz startet mit 5s-Periode
  3. Observer mitteilen GPS-Empfang erfolgreich. Dann stoppen der Instanz.

Controllerschicht

[Bearbeiten]

Zentrale Controller Klasse

[Bearbeiten]

Das zentrale Objekt in der Controller Schicht ist das MobileJavaMapMIDlet und erbt von der abstrakten MIDlet Klasse. MobileJavaMapMIDlet holt über eine statische Konstruktormethode eine Instanz der Controller Klasse bei Initialisierung. Das Singleton Pattern wird implementiert, denn nur eine Instanz wird benötigt. Die Kontaktfläche erzeugt die Controller Klasse durch einen privaten Konstruktor: Model, View,...In der Controller Klasse befindet sich die nicht-statische, verschachtelte ActionThread Klasse. Die ActionThread Klasse erbt von Thread. Separate Plug-in Klassen können die Initialisierungen aufnehmen. Die Auslagerung in ein Plug-in implementiert das IPlugIn Interface. IPlugIn Interface enthält die Methoden zum Starten und Zerstören der Plug-ins. Die Reihenfolge der Plug-in Abläufe ist wesentlich. Es gibt nur eine Implementierung des Prototyp das ConfigurationPlugIn. ConfigurationPlugIn lies aus einem RecordStore aus, beim Beenden schiebt es die aktuelle Konfiguration wieder in den RecordStore rein. Der Controller kann dann schlank bleiben.

Action-Thread Konzept

[Bearbeiten]

Das Design von Sun

[Bearbeiten]

Die Sun-Entwicklerwebseite hat eine J"ME-Beispiel-Applikation (Java Smart Ticket Sample Application) mit Designvorschlägen und Patterns für J2ME Applikationen. Diese Applikation setzt auf eine zentrale Controllerklasse (UIController) in der eine nicht-statische, verschachtelte Klasse namens Eventhandler lebt. Eventhandler ist Kindklasse von java.lang.Thread. Eine durchzuführende Aktion ist durch die handleEvent Methode der Controller Klasse aufzurufen. Die Parameter sind ein Integerwert (die Event-ID) und ein Object Feld. Die Event-ID bestimmt die auszuführende Aktion, die Parameter dafür speichert das Objektfeld. Die aufzurufende Methode erzeugt eine neue Instanz der EventHandler Klasse. Im Konstruktor wird die erhaltende Event-ID und das Objekt-Feld ergänzt. Die aufrufende Methode ruft die start-Methode auf in der EventHandler Klasse und erzeugt einen neuen Thread. Dieser Thread entscheidet anhand der Event-ID, welcher Code ausgeführt werden soll.

Bessere Lösung durch Action Threads

[Bearbeiten]

Die Aktionen werden in Thread gekapselt und implementieren alle die gleiche Interface. Bevor der Thread aufgeweckt wird, wird dem Thread Objekt das auszuführende Aktionsobjekt übergeben. Die Idee stammt aus dem Entwurfsmuster "Command" mit dem Unterschied, dass ein Aktionsobjekt mehrere Empfänger besitzen kann gegen einen Empfänger im Entwurfsmuster Command.

Alle Aktionsobjekte implementieren das IAction Interface in der die Methoden execute und cancel der Aktionen drin stehen. Eine Referenz auf das Controller ist der Übergabeparameter. Ereignisse in der View-Klasse erzeugen die Aktionsobjekte. Falls ein IAction Objekt einmal primitive Daten braucht kann es explizit von einem Konstruktor übergeben werden, das ist der Ausnahmefall, wenn die primitiven Daten nicht aus der Controller lasse stammen. Das Single-Worker-Thread enthält die Methoden notifyAction und cancelAction, sie ist repräsentiert durchdie Klasse ActionThread.

Action Threads

[Bearbeiten]

Ist alles konsistent

[Bearbeiten]

View Schicht

[Bearbeiten]

MobileJavaMap verletzt das MVC Konzept, weil die nicht alle View-Klassen (Higl-Level-LCDUI Komponenten) die Modellklassen kennen. Die Ersatzlösung füllt die notwendigen Aktionsklassen mit Daten vor der Anzeige.

Im folgenden betrachten wir die Interaktionen der Viewklassen mit dem Controller. Wir beschäftigen uns auch mit der eigentlichen Darstellung der Karte.

High-Level-LCDUI Komponenten für die Menüführung

[Bearbeiten]

Die High-Level-LCDUI Komponenten werden verwendet um die Menüführung zu machen. Die High-Level-LCDUI Komponenten leiten dabei von javax.microedition.lcdui.List oder javax.microedition.lcdui.Form ab, das entscheidet der Verwendungszweck der der Viewklasse. Die Form Klasse repräsentiert ein Formular mit den Formularelementen Textfelder, Datumsfelder oder Auswahllisten. Die List Objekte werden für die Darstellung von Listen verwendet. Beide Klassen Form und List sind von der abstrakten Screen Klasse abgeleitet. Die Screen Klasse ist die Basis-Klasse für alle High-Level LCDUI Komponenten.

Konkretes Beispiel für ein Formular in MobileJavaMap ist die OptionsUI Klasse für die Repräsentation des Optionsmenüs. Denn die OPtionseinstellungen benötigen Textfelder und eine Auswahlliste. DAs Startmenü von MobileJavaMap ist einfacher unb braucht nur eine Auswahlliste und ist nur eine Ableitung der StartUI Klasse von List.

Bevor eine View Klasse angezeigt wird, füllt der Controller sie bei Bedarf mit den anzuzeigenden Werten. Die Werte ändern nur die Viewklassen OptionsUI und MapListUI. Die MapListUI stellt die Karte in Listenform dar. Die zugehörige Modellobjekt verändert sich nicht zum Darstellungszeitpunkt und ist nicht zu überwachen. Jede Viewklasse erzeugt im Konstruktor die notwendige Command Objekte und implementiert den eigenen CommandListener. Bei einem Command Ereignis erzeugt die Viewklasse das passende IAction Objekt und übergibt es der Controller Instanz zur Durchführung.

Eine konkreter Ablauf, wenn das Startmenü das Optionsmenü aufruft:

1. Die commandAction Methode der StartUI Klasse erzeugt eine neue Instanz der ShowOptionsAction und übergibt sie dem Controller.
2. Der wiederrum übergibt das Objekt an die ActionThread.
3. Der ActionThread ruft die execute Methode der ShowOptionsACtion auf.
4. execute holt die Werte aus dem Configuration Objekt und füllt das OptionsUI Objekt mit den darzustellenden Werten.
5. Am Ende bringt die execute Methode das OptionsUI Objekt auf dem Bildschirm.

Beim Prototyp sind die Modellklassen nicht zu überwachen, weil sie sich nicht ändern. Ist der Prototyp einmal anzupassen, dann ist das nach dem MVC-Muster zu überarbeiten:

Die Viewklassen implementieren dabei entsprechende Observer Interfaces und bekommen das Modellobjekt im Konstruktor übergeben. Die jeweiligen Aktonsklassen wie ShowOptionsAction dürften den ZUstand der Viewklasse nicht mehr ändern, sondern sie nur noch auf dem Bildschirm bringen.

Low-Level-LCDUI Komponenten für die Kartenherstellung

[Bearbeiten]

Die Karte wird dargestellt mit den Low-Level API, wir fügen mit ihnen die einzelnen Kacheln zu einem Kartenausschnitt zusammen. Die Scrollen braucht die eine instantane Ereignisreaktion durch den Tastendruck. In einer CLDC/MIDP Umgebung geht das nur mit der Low-Level API.

Laut dem Anforderungskatalog muss die Darstellung in der Lage sein, einzelne Schichten/Overlays über die eigentliche Karte zu legen. Zum Beispiel die Anzeige aller Interessens-Gruppenangehörige auf dem Bildschirm.

Das MobileJavaMap implementiert einen eigenen LayerManager, eine eigene Layer Klasse und eine MapLayer Klasse. Die MapLayer Klasse zeichnet die wartenden Kacheln im ISection Objekt. Der paint() Aufruf zeichnet das MapLayer Objekt die in der Sektion enthaltenen Kacheln auf dem Bildschirm. Die Layer Klasse ist identisch mit dem Original, aber die LayerManager Klasse nicht. Die LayerManager Klasse kann die ViewWindows durch mehrere Observer überwachen und unterstützt die PixelCoordinate Klasse. Die weiteren Unterklassen von Layer sind POILayer ("Point of Interest" Layer) und ReferencePointLayer. POILayer sind prototypische Demonstrationsklassen für die Darstellung von mehreren "Point Of Interest". ReferencePointLayer zeichnet den zuvor gesetzten Referenzpunkt.

Die Reihenfolge des Einsatzes regelt die Prioritätsvergabe. Die MapLayer Instanz hat die höchste und die ReferencePointLayer die geringste Priorität. Beginnend mit dem Layer der höchsten Priorität ruft der LayerManager beim Zeichnen die einzelnen paint Methoden der Layer auf. Für das Aufrufen der LayerManager Instanz ist die von Canvas abgeleitete Klasse MapUI Klasse verantwortlich. In ihrer paint Methode ruft sie die paint Methode der LayerManager Instanz auf. Um auf Tastatureingaben reagieren zu können, startet die MapUI Klasse einen eigenen Thread und fragt den Tastaturstatus ab für die Neuzeichnung des Displays.

Im Gegensatz zu den High-Level-LCDUI Komponenten kennt die MapUI Klasse ihr Modellobjekt (das I-Map Objekt) und reagiert auch auf Ereignisse. Beispielsweise implementiert die MapUI Klasse das IGPSObserver Interface und observiert damit eine IGPSReceiver Instanz mit dem periodischen Senden neuer GPS-Positionsdaten an ihre Observer. Beim Emfang einer neuen GPS-Signals zentriert die MapUI Klasse die Karte zur empfangenen Position.