Datenhaltung

Phillipp Bertram, Peer Wagner

Die Entwicklung auf einem Smartphone bedeutet im allgemeinen eine große Umstellung im Gegensatz zur herkömmlichen Softwareentwicklung. Soviel moderne Smartphones auch zu leisten im Stande sind, so beschränkt sind sie dennoch aus der Sicht von Desktopcomputern, die eine Vielzahl an Möglichkeiten bieten oder anders gesagt kaum noch einer Einschränkung unterliegen. Die Datenhaltung und auch der Zugriff und die Zugriffskontrolle sind jedoch auf einem beschränkten Mobilgerät ein wichtiger Aspekt. Dies bedeutet, dass bereits der Entwurf einer vernünftigen Datenhaltung gut strukturiert werden sollte und das Datenmodell dementsprechend an bestimmte mobile Konzepte angepasst werden muss.

Für den Entwickler präsentieren sich direkt zwei unterschiedliche Lösungsmöglichkeiten, die im folgenden näher beleuchtet werden sollen.

Datenhaltung in einer Datenbank

Der Ansatz Daten in einer relationalen Datenbank zu halten ist für die meisten Entwickler sicherlich einer der offensichtlichsten Möglichkeiten. Diese Möglichkeit bietet sich auch auf einem Android-System mit der SQLite1 Bibliothek, welche eine vollständige Datenbankimplementierung darstellt. SQLite behauptet von sich selbst besonders klein, schnell und zuverlässig zu sein. Dies sind natürlich Eigenschaften, wie sie auf einem mobilen System absolut wünschenswert sind.

Android spezifische Datenhaltung mit Content Providern

Um in einer Applikation eine Datenbank aufzusetzen und zu benutzen sind nur wenige Schritte notwendig. Die Anweisungen unterscheiden sich nur in wenigen Kleinigkeiten von Anweisungen die für andere Datenbanken benutzt werden. Android-spezifische Konzepte kommen eher bei der Darstellung von Daten aus einer Datenbank, als auch bei der Bereitstellung der Daten zum Einsatz. Bei Ersterem wird oftmals direkt vom System ein Cursor einer Abfrage weiterverarbeitet und dargestellt. Die Bereitstellung der Daten ist in einem Android-System dann oftmals modular gehalten. Diese Modularität wird durch den Einsatz von Content Providern erzeugt. Hierbei handelt es sich um eigenständige Activities oder sogar Applikationen, die eine fest definierte Schnittstelle auf die zur Verfügung gestellten Daten umsetzen. Damit kann jede andere Activity oder Applikation, die an die Daten heran möchte, eine Anfrage an den Content Provider stellen. Genau dieses Prinzip wird zum Beispiel bei hinterlegten Kontaktdaten wie dem Telefon- oder auch Adressbuch gemacht. Diese Art des Zugriffs ist jedoch nicht nur wegen seiner Einfachheit beliebt, er ist zudem auch die einzige Möglichkeit Daten zwischen Applikationen auszutauschen. Das sonst verwendete Rechtemanagment auf einem Android-System lässt den Zugriff auf Daten fremder Applikationen aus Sicherheitsgründen nämlich nicht zu.

Gegenüber den Vorteilen und der Einfachheit eine Datenbank auf einem Android-System einzusetzen, gibt es, besonders für unsere Applikation, einen entscheidenden Nachteil. Daten in einer Datenbank sind nicht ohne Weiteres dafür geeignet Echtzeitdaten vorzuhalten. Alles andere würde auch keinen Sinn ergeben, denn gerade wenn sich die Spieler über die Spielfläche bewegen oder auch einen Tresor lösen möchten, sollten die Daten, die diesen Schritten zugrunde liegen nicht mehrere Minuten alt sein. Es kommt außerdem hinzu, dass ein Spieler, der das Spiel unterbricht und zu einem späteren Zeitpunkt fortführt, einen komplett neuen Datensatz benötigt.

Datenhaltung in Objekten

Die zweite und ebenfalls augenscheinliche Option, Daten in Objekten und damit im Speicher zu halten, ist auf einem Android-System in keiner Weise vom Standardverhalten anderer Programmiersprachen und Konzepte zu unterscheiden. Einzig ist auf den Lebenszyklus und den damit möglichen Datenverlust in anderen Activities zu achten. Dieses Thema ist jedoch in der Einführung der Android-Konzepte genauer beschrieben.

Das wir uns in unserer Applikation für die Datenhaltung in Objekten/Speicher entschieden haben, ist bereits im oberen Abschnitt beschrieben worden. Es sei noch einmal erwähnt, dass die gesamte Spielidee darauf beruht, dass die Spieler in Echtzeit miteinander das Spiel spielen und sich daher im Sekundentakt Änderungen ergeben können. Der Datenhaltung im Speicher würde als einziger Punkt entgegensprechen, dass selbst moderne Smartphones einen begrenzten Platz an Arbeitsspeicher zur Verfügung haben. Diesem Punkt kann jedoch von unserer Seite die geringe Datenmenge entgegen gesetzt werden, womit die Speicherbegrenzung keine Rolle mehr spielt. Auch wenn sich im Laufe der Entwicklung verschiedene Speicherprobleme ergeben haben, so waren dies in allen Fällen fehlerhafte Freigaben des Systems und keine Engpässe auf Grund der vorzuhaltenden Datenmenge.

Das unten stehende Bild zeigt einige Strukturen, wie sie für das Modell verwendet werden und wird im weiteren genauer beschrieben.

Abb. 1: Skizze der Datenhaltung in der Applikation auf dem Android-System

Die Datenhaltung hat ihren eigenen Bereich bekommen. So wurde versucht die Applikation nach dem Model-View-Controller Paradigma zu entwickeln, um den logischen Teil von den Daten und den Ansichten zu trennen. Wie in der allgemeinen Beschreibung des Android-Systems zu lesen ist, ist diese Trennung jedoch nicht vorgesehen und damit an manchen Stellen schwierig umzusetzen.

Jede Activity ist in diesem Bild grob als Controller zu verstehen. Sie steht damit ganz oben und regelt was und wie etwas angezeigt werden soll. Die View-Ebene ist für diese Betrachtung allerdings ohne Bedeutung und findet sich daher nicht weiter im gezeigten Bild. Eine Activity ist hier also als nicht näher spezifizierter Controller zu verstehen, der irgendwie an die Daten gelangen muss. Hierfür wird die ModelFactory eingesetzt. Sie ist ein Singleton und dient dazu, alle Model-Implementierungen zu erzeugen und zu verwalten. Die verschiedenen Modelle speichern logische Datenblöcke. Es gibt zum Beispiel ein Modell für den Chat, eines für die Tresore und eines für das Inventar. Sie werden alle unter dem Bezeichner xyz-Model in der Grafik ausgedrückt. Die ModelFactory erstellt außerdem ein Requester-Objekt. Dieses Objekt beinhaltet die Methoden für die Kommunikation mit dem Server und ist die einzige Schnittstelle zu diesem. Alle Modelle müssen wohlgeformte Anfragen an den Requester übergeben und bekommen dann bei Anfragen eine Antwort mitgeteilt. Die Kompression des Datenstroms ist ebenfalls eine Aufgabe des Requesters.

Nun gibt es noch drei weitere Objekte, die direkt oder auch indirekt mit dem Modell interagieren. Zunächst sei das SharedData Objekt beschrieben. Diese Klasse beinhaltet einige eindeutige Daten, die Modellübergreifend Gültigkeit haben. Darunter fallen die aktuelle Session-ID, der Spielername, die Teamzugehörigkeit, und eine Spiel-ID. Alle Modelle, die an Änderungen dieser Felder interessiert sind, können sich über ein Observer-Observable-Pattern am SharedData-Objekt registrieren.

Die beiden letzten unbeschriebenen Objekte, das UpdateModel und der UpdateService gehören gewissermaßen zusammen. Der UpdateService ist eine eigene Activity, die in einem getrennt von der restlichen Applikation laufendem Thread ausgeführt wird. Es handelt sich dabei im Grunde genommen um einen Timer, der zu festgelegten Zeiten das UpdateModel zu einer Update-Anfrage anregt. Dies hat seinen Grund darin, dass regelmäßige Updates nicht den Hauptthread blockieren sollen. Das UpdateModel ist hierbei erst einmal als normales Model zu betrachten. Die Besonderheit ist, dass sich bei dem UpdateModel jedes xyz-Model registrieren kann, dies ebenfalls im Observer-Observable-Pattern, um über allgemeine Updates informiert zu werden. Die Modelle sollten dann in ihren Update-Methoden die eigenen Daten verändern. Die Modelle selbst sind dann ebenfalls observable, so dass sich Activities an ihnen registrieren und ein Update der Views einleiten können.

Datenhaltung auf dem iPhone und Notifications

Das Grundkonzept stimmt größtenteils mit dem Konzept der Datenhaltung beim Android überein. Lediglich ein paar iPhone spezifische Änderungen mussten vorgenommen werden. Während die Kommunikation zwischen den Objekten beim Android weitgehend über das Observable-Pattern implementiert wurde, stellt Apple von Haus aus ein sehr nützliches Notification Feature zur Verfügung. Notification ist ein System, welches registrierte Objekte über Änderungen irgendwo innerhalb der Applikation benachrichtigt und die entsprechenden Methoden aufruft. Üblicherweise bekommen Objekte ihre Informationen über die an sie geschickten Messages. Das bedeutet auch, dass das Objekt, welches die Message verschickt auch wissen muss, welche Objekte diese Änderungen mitkriegen wollen und welche Methode aufgerufen werden soll. Notification ist ein Broadcast-Modell, wo man Objekte registrieren kann, die benachrichtigt werden sollen. Notifications werden von einer Singleton-Klasse NSNotificationCenter verwaltet. Das Objekt dieser Klasse ist über defaultCenter zu erreichen und mit folgendem Code-Beispiel kann sich ein Objekt registrieren.

[[NSNotificationCenter defaultCenter] addObserver:self
                                      selector:@selector(updateAreaVisibilities)
                                      name:@"notif_effects" object:nil];

In diesem Fallt registriert sich ein Objekt selber (addObserver:self) und gibt an, dass die Methode updateAreaVisibilities aufgerufen werden soll, wenn die Notification notif_effects gepostet wird. Sobald irgendwo in der Applikation in etwa dieser Code aufgerufen wird

[[NSNotificationCenter defaultCenter] postNotificationName:@"notif_effects" object:nil];

werden die Methoden der Objekte, die auf die Notification notif_effect registriert sind, aufgerufen und ausgeführt. Im iPhone wird dieses Konzept vor allem in den Models verwendet. Wenn das UpdateModel vom Server z.B. eine Benachrichtigung bekommt, dass ein Spieler eine Kachel aufgedeckt hat, postet es diese Notification.


1 http://www.sqlite.org Offizielle SQLite Homepage


Page last modified on March 21, 2011, at 12:55 PM