3. Persistenz und Datenbanken Lernziele 3. Persistenz und Datenbanken Themen/Lernziele: • Einstellungen • Dateien lesen und schreiben • Datenbanken mit SQLite • Allgemeine Schnittstelle zu Datenquellen: Content Provider Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 202 3. Persistenz und Datenbanken Lernziele Android Technologien zur persistenten Speicherung • Shared Preferences: Schlüssel/Wert-Paare • Files: Schreiben und lesen von Dateien mit der Java-API, Speicherung intern oder auf Speicherkarte • SQLite Datenbanken: Jede Anwendung kann ihre eigene SQLite Datenbank verwalten • Content Provider: Allgemeine Schnittstelle für den Datenzugriff und die Manipulation über Anwendungsgrenzen hinweg Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 203 3. Persistenz und Datenbanken Shared Preferences Speicherung von Schlüssel/Wert-Paaren Prinzipiell zwei Techniken: • SharedPreferences: persistente Speicherung der Paare, Zugriff innerhalb des selben Kontextes • Bundle: Speicherung von Paaren zur Sicherung von Activity-Zuständen Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 204 3. Persistenz und Datenbanken Shared Preferences Shared Preferences • Klasse SharedPreferences • Zugriff über den Kontext mit der Methode getSharedPreferences() • Parameter: Name für eine Sammlung von Schlüssel/Wert-Paaren, Modus • Beispiel: SharedPreferences myPrefs = getSharedPreferences("myPrefs", Activity.MODE_PRIVATE); Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 205 3. Persistenz und Datenbanken Shared Preferences • Physische Speicherung in: /data/data/package /shared prefs/myPrefs.xml • Lesender Zugriff auf die Paare: getXXX(), wobei XXX für einen Datentyp steht. • Beispiele: boolean float int String boolPref = myPrefs.getBoolean("booleanPref", false); lastFloat = myPrefs.getFloat("lastFloat", 0f); gameLevel = myPrefs.getInt("gameLevel", 1); email = myPrefs.getString("email", "[email protected]"); • 1. Parameter: Schlüssel, 2. Parameter: Default-Wert Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 206 3. Persistenz und Datenbanken Shared Preferences Änderungen von Shared Preferences • Mittels SharedPreferences.Editor • Editor mit Methode edit() erzeugen: SharedPreferences.Editor editor = myPrefs.edit(); • Zur Speicherung: putXXX() • 1. Parameter: Schlüssel, 2. Parameter: neuer Wert Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 207 3. Persistenz und Datenbanken Shared Preferences • Beispiel: editor.putBoolean("booleanPref", true); editor.putFloat("lastFloat", 1f); editor.putInt("gameLevel", 2); editor.putString("email", "[email protected]"); • Zur Sicherung der Änderungen: commit() editor.commit(); Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 208 3. Persistenz und Datenbanken Shared Preferences Shared Preferences für Einstellungs-Dialoge • Layout-Klasse für Einstellungs-Dialog: PreferenceScreen • Views für Einstellungen: z.B. CheckBoxPreference, ListPreference • Allgemeine Attribute: – android:key: Der Schlüssel – android:title: Titel für die Einstellung (groß) – android:summary: Erläuterung für die Einstellung (klein, unterhalb von Titel) – android:defaultValue: voreingestellter Wert Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 209 3. Persistenz und Datenbanken Shared Preferences • Zusätzliche Attribute für ListPreference: – android:entries: Array (String) der anzuzeigenden Listeneinträge (Texte, sprachspezifisch) – android:entryValues: Array mit den Werten zu den Einträgen (sprachunabhängig) – android:dialogTitle: Titel zur Auswahlliste Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 210 3. Persistenz und Datenbanken Shared Preferences <?xml version="1.0" encoding="UTF-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/ <CheckBoxPreference android:key="entrydialog" android:title="@string/set_entrydiag_title" android:summary="@string/set_entrydiag_summary" android:defaultValue="true"/> <ListPreference android:key="cursorform" android:title="@string/set_cursor_title" android:summary="@string/set_cursor_summary" android:entries="@array/cursor_forms" android:entryValues="@array/cursor_form_values" android:defaultValue="block" android:dialogTitle="@string/set_cursor_dialog_title"/> <ListPreference Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 211 3. Persistenz und Datenbanken Shared Preferences android:key="defsqform" android:title="@string/set_defsquare_title" android:summary="@string/set_defsquare_summary" android:entries="@array/defsquare_forms" android:entryValues="@array/defsquare_form_values" android:defaultValue="block" android:dialogTitle="@string/set_defsquare_dialog_title"/> </PreferenceScreen> Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 212 3. Persistenz und Datenbanken Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 Shared Preferences 213 3. Persistenz und Datenbanken Shared Preferences Activity für Einstellungs-Dialoge • PreferenceActivity als Unterklasse von Activity • Üblicherweise bildet man wiederum Unterklasse von PreferenceActivity • Import des Einstellungs-Layout in onCreate() mittels addPreferencesFromResource() • Gute Vorgehensweise: Für jede Einstellung eine Klassenmethode für die Abfrage anbieten, evtl. auch für Änderung • Zugriff auf SharedPreferences mit Hilfe des PreferenceManager Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 214 3. Persistenz und Datenbanken Shared Preferences • Beispiel lesen: public static boolean getEntryDialog(Context context) { return PreferenceManager.getDefaultSharedPreferences(context). getBoolean(ENTRY_DIALOG_KEY, ENTRY_DIALOG_DEFAULT); } • Beispiel schreiben: public static void putEntryDialog(Context context, boolean value) SharedPreferences.Editor editor = PreferenceManager. getDefaultSharedPreferences(context).edit(); editor.putBoolean(ENTRY_DIALOG_KEY, value); editor.commit(); } Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 215 3. Persistenz und Datenbanken Shared Preferences • Zum Starten der PreferenceActivity: public void onShowSettings() { startActivity(new Intent(this,SettingsLayout.class)); } SettingsLayout ist hier von PreferenceActivity abgeleitet. • Nicht vergessen: Manifest erweitern! <activity android:name=".SettingsLayout" android:label="Settings"> </activity> Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 216 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Statische Dateien als Ressourcen • Dateien in Verzeichnis res/raw/ ablegen, z.B. res/raw/meineDatei • Es wird automatisch erzeugt: R.raw.meineDatei • Zugriff über Resources und die Methode openRawResource(): Resources res = getResources(); InputStream meineDatei = res.openRawResource(R.raw.meineDatei); • nur lesender Zugriff • mit Streams die üblichen Operation aus java.io möglich Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 217 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Aufbau/Zugriff Dateisystem • Anwendungsverzeichnis: /data/data/package / • In das Anwendungsverzeichnis darf nur die Anwendung selbst schreiben! • Spezielle API-Methoden aus android.content.Context erforderlich • Verschiedene Unterverzeichnisse möglich • Alternative: SD-Karte Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 218 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien • SD-Karte erreichbar via /sdcard • Nutzung der gewöhnlichen java.io Methoden Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 219 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Zugriff auf Dateien im Anwendungsverzeichnis • FileOutputStream oder FileInputStream erzeugen mit Instanzmethoden openFileOutput() oder openFileInput() (Paket android.content.Context) • Beispiel: FileOutputStream fos = openFileOutput("myFile.txt", MODE_PRIVATE); FileInputStream fis = openFileInput("myOtherFile.txt"); • Pfadnamen darf / nicht enhalten! Ansonsten Exception • Bei openFileOutput() wird Datei automatisch neu angelegt oder überschrieben. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 220 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien • Anhängen statt Überschreiben: Context.MODE APPEND beim zweiten Parameter • Physische Ablage in Verzeichnis /data/data/package /lib • Bei MODE PRIVATE kein Sharing zwischen Anwendungen • Alternativen: Flags MODE WORLD READABLE, MODE WORLD WRITEABLE, verknüpfbar Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 221 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Datei-Management: Anwendungsverzeichnis siehe android.content.Context, Beispiele: • fileList() liefert ein String-Array mit Dateinamen zur Anwendung • deleteFile(): Löschen von Dateien • getFilesDir(): Liefert den Pfad, in dem die Dateien der Anwendung abgelegt werden, als Instanz von java.io.File • getDir(): Liefert ein Unterverzeichnis zum Anwendungsverzeichnis als Instanz von java.io.File Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 222 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Datei in öffentlichem Unterverzeichnis anlegen File pubVerz = getDir("Personal" | MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE); File akte = new File(pubVerz, "akte.txt"); FileOutputStream out = new FileOutputStream(akte); ... • Berechtigungen des Verzeichnisses gelten nicht für die Datei! • Ablage in /data/data/package /app Personal Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 223 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Dateien aus Unterverzeichnis lesen File pubVerz = getDir("Personal" | MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE); File akte = new File(pubVerz, "akte.txt"); FileInputStream out = new FileInputStream(akte); ... Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 224 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Dateien aus Anwendungsverzeichnis/Unterverzeichnis löschen • Dateien, die mit openFileOutput() erzeugt wurden, werden mit deleteFile() gelöscht. • Alle anderen Dateien wirden mit der Methode delete() der Klasse java.io.File gelöscht. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 225 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien Zugriff auf die SD-Karte • Eintrag der notwendigen Permission im Manifest: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> • Für Zugriff gewöhnliche Methoden aus Paket java.io. • Nützliche Methoden aus Paket android.os: – getExternalStorageDirectory() liefert das Wurzelverzeichnis der SD-Karte als Instanz von java.io.File – getExternalStorageState() liefert Informationen zur Verfügbarkeit Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 226 3. Persistenz und Datenbanken Datenbanken mit SQLite Datenbanken mit SQLite • Open Source • weitgehend konform zum Standard SQL-92 • leichtgewichtig • Einbindung über C-Bibliothek • Weitere Informationen: www.sqlite.org Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 227 3. Persistenz und Datenbanken Datenbanken mit SQLite Manifest Typing In manifest typing, the datatype is a property of the value itself, not of the column in which the value is stored. SQLite thus allows the user to store any value of any datatype into any column regardless of the declared type of that column. ☞ Die Angabe der Datentypen bei create table sind nur ein Hinweis an die Datenbank, sie müssen nicht eingehalten werden. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 228 3. Persistenz und Datenbanken Datenbanken mit SQLite Keine Unterstützung von ... • Java Database Connectivity (JDBC) • referentielle Integrität (foreign key) • bestimmte Join-Arten wie right outer join und full outer join • bestimmte Arten von alter table Anweisungen Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 229 3. Persistenz und Datenbanken Datenbanken mit SQLite Anlegen/Öffnen einer Datenbank • üblicherweise mittels SQLiteOpenHelper einer Instanz einer Unterklasse von • Konstruktorparameter von SQLiteOpenHelper: – – – – Context, z.B. die Activity Name der Datenbank Instanz einer Cursor-Factory, wenn nicht notwendig == null Versionsnummer der Datenbank Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 230 3. Persistenz und Datenbanken Datenbanken mit SQLite • In Unterklasse überschreibt man die folgenden Methoden von SQLiteOpenHelper: – public void onCreate(SQLiteDatabase db) Wird aufgerufen, wenn die Datenbank bisher nicht existiert. Enthält typischerweise Anweisungen zum Erzeugen der Datenbank-Relationen. – public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) Wird aufgerufen, wenn beim Öffnen der Datenbank eine höhere Versionsnummer angegeben wird, als beim letzten Öffnen. Enthält Anweisungen zum Upgrade der Datenbank auf newVersion. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 231 3. Persistenz und Datenbanken Datenbanken mit SQLite • Methoden von SQLiteOpenHelper zum Anlegen/Öffnen einer Datenbank: – public SQLiteDatabase getWriteableDatabase() Create and/or open a database that will be used for reading and writing. – public SQLiteDatabase getReadableDatabase() Create and/or open a database. • Ohne Nutzung von SQLiteOpenHelper: Mittels der Methode public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) auf Context-Objekt Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 232 3. Persistenz und Datenbanken Datenbanken mit SQLite Methoden für SQLiteDatabase Einige Methoden zur Verwaltung und Transaktionssteuerung: • void close() • void beginTransaction() • void endTransaction() • int getVersion() • boolean isOpen() Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 233 3. Persistenz und Datenbanken Datenbanken mit SQLite DDL-Anweisungen • SQL-Anweisungen, die keine Anfragen sind, können stets mittels public void execSQL(String sql) ausgeführt werden. • z. B. create table, insert, etc. • Keine Unterstützung mehrerer Anweisungen! • Ungültige SQL-Anweisungen lösen eine SQLException aus. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 234 3. Persistenz und Datenbanken Datenbanken mit SQLite Anfragen Möglichkeiten zur Durchführung von Anfragen: • Raw Queries • Regular Queries • mit Hilfe eines SQLiteQueryBuilder Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 235 3. Persistenz und Datenbanken Datenbanken mit SQLite Raw Queries • public Cursor rawQuery (String sql, String[] selectionArgs) • SQL-Anfrage: sql • falls sql Anfrage vollständig qualifiziert, dann ist selectionArgs == null • sql kann in WHERE-Klausel “?” als Platzhalter für Parameter enthalten dann Übergabe der Parameterwerte mit Hilfe von selectionArgs Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 236 3. Persistenz und Datenbanken Datenbanken mit SQLite Regular Queries public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) • distinct: Duplikatelimination oder nicht • table: Relationenname • columns: Spaltennamen für die Projektion • selection: Tupelbedingung, kann “?” als Platzhalter enthalten Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 237 3. Persistenz und Datenbanken Datenbanken mit SQLite • selectionArgs: Parameter für die Platzhalter in selection • groupBy: Spaltennamen für die Gruppierung • having: Gruppenbedingung • orderBy: Festlegung der Reihenfolge der Tupel • limit: Maximale Anzahl an Tupeln, die die Anfrage liefern soll Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 238 3. Persistenz und Datenbanken Datenbanken mit SQLite Cursor • Query liefert eine Cursor-Instanz • Ein Cursor ist ein Fenster auf das Ergebnis einer Anfrage: jeweils ein Tupel ist das aktuelle Tupel • Cursor stellt Methoden zur Navigation innerhalb des Ergebnisses bereit • Weiterhin Methoden für den Zugriff auf die Werte des aktuellen Tupels Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 239 3. Persistenz und Datenbanken Datenbanken mit SQLite Cursormethoden • public boolean moveToFirst() Setzt den Cursor auf das erste Tupel der Ergebnismenge. • public boolean moveToNext() Setzt den Cursor auf das nächste Tupel der Ergebnismenge. • public boolean moveToPrevious() Setzt den Cursor auf das vorhergehende Tupel der Ergebnismenge. • public int getCount() Liefert die Anzahl der Tupel in der Ergebnismenge. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 240 3. Persistenz und Datenbanken Datenbanken mit SQLite • public int getColumnIndex(String colName) Liefert den Spaltenindex zu einem Spaltennamen. • public String getColumnName(int colIndex) Liefert den Spaltennamen zu einem Spaltenindex. • public String[] getColumnNames() Liefert ein Feld der Spaltennamen. • Für die Ermittlung der Werte stehen Getter-Methoden in Abhängigkeit vom Datentyp zur Verfügung: public Datentyp getDatentyp (int spaltenIndex) Datentypen: int, long, short, double, float, String Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 241 3. Persistenz und Datenbanken Datenbanken mit SQLite • public void close() Schließen des Cursors. • Mit Hilfe der Methoden deactivate() und requery() kann ein Cursor vorübergehend deaktiviert und anschließend wieder aktualisiert werden. Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 242 3. Persistenz und Datenbanken Datenbanken mit SQLite DML-Anweisungen • DML: Data Manipulation Language • Insert, Update, Delete • Immer möglich mittels execSQL() • Nachteil: Komplette SQL-Anweisung muss als String aufgebaut werden. • Alternative: ContentValues Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 243 3. Persistenz und Datenbanken Datenbanken mit SQLite ContentValues • Dient eigentlich zur Speicherung von Werten, die ein ContentResolver verarbeiten kann. • Auch für SQLite-Datenbanken einsetzbar. • Schema zum Einfügen eines neuen Tupels: ContentValues tupel = new ContentValues(); tupel.put(Spalten-Name , Wert ); ... db.insert(Tabellen-Name , null, tupel); Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 244 3. Persistenz und Datenbanken Datenbanken mit SQLite • Update mit Hilfe von: db.update(Tabellen-Name, tupel, where, null) where: Selektionsbedingung analog zur WHERE-Klausel, um die zu ändernden Tupel zu bestimmen. • Delete analog mit: db.delete(Tabellen-Name, where, null) Entwicklung mobiler Anwendungen — Europäische Fachhochschule Brühl/Neuss, 3. Quartal 2014 245