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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 189 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 190 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 191 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); Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 192 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 193 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 194 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(); Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 195 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 196 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 197 3. Persistenz und Datenbanken Shared Preferences <?xml version="1.0" encoding="UTF-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/andro <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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 198 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> Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 199 3. Persistenz und Datenbanken Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 Shared Preferences 200 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 201 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(); } Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 202 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> Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 203 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 204 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 205 3. Persistenz und Datenbanken Lesen und Schreiben von Dateien • SD-Karte erreichbar via /sdcard • Nutzung der gewöhnlichen java.io Methoden Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 206 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 207 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 208 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 209 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 210 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); ... Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 211 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 212 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 213 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 214 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 215 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 216 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 217 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 218 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 219 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() Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 220 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 221 3. Persistenz und Datenbanken Datenbanken mit SQLite Anfragen Möglichkeiten zur Durchführung von Anfragen: • Raw Queries • Regular Queries • mit Hilfe eines SQLiteQueryBuilder Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 222 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 223 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 224 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 225 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 226 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 227 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 228 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. Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 229 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 Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 230 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); Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 231 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) Mobile Informationssysteme I — Hochschule Bonn-Rhein-Sieg, Sommersemester 2012 232