Dazu werden wir drei Java-Klassen mit Hilfe von Android Studio anlegen. Jede dieser Klassen übernimmt eine bestimmte Aufgabe bei der Arbeit mit dem SQLite Datenbanksystem.
Doch bevor wir die Klassen anlegen, werden wir uns ausführlich mit dem SQLite Datenbanksystem befassen und dabei auch auf die Frage eingehen, wie SQLite in das Android System integriert ist.
Anschließend beschreiben wir auf welche Art die SQLite Datenbank in unsere Einkaufslisten-App integriert werden soll. Dabei gehen wir auch auf die drei zu erstellenden Java-Klassen näher ein.
Wir stellen jede der drei Klassen einzeln vor und erklären wofür wir die jeweilige Klasse benötigen.
Am Ende der Lektion werden wir überprüfen, ob die neuen Klassen ordnungsgemäß angelegt wurden und dazu die Log-Meldungen in Android Studio überwachen.
In dieser Lektion lernt ihr:
- Was ist das SQLite Datenbanksystem und wie ist SQLite in Android integriert
- Einsatz der SQLite Datenbank in unserer Android App
- ShoppingMemo-Klasse: Sie repräsentiert die Datensätze
- ShoppingMemoDbHelper-Klasse: Sie erzeugt die SQLite Datenbank
- ShoppingMemoDataSource-Klasse: Sie regelt die Datenbankzugriffe
- Testcode in MainActivity einfügen
- Ausführen und Überprüfen unserer Android SQLite App
Das Android SQLite Tutorial:
- Teil 1: Android SQLite Projekt anlegen
- Teil 2: SQLite Datenbank integrieren
- Teil 3: Tabelle in Datenbank erstellen
- Teil 4: Daten in Datenbank schreiben
- Teil 5: Auf Eingaben reagieren
- Teil 6: Daten aus Datenbank löschen
- Teil 7: Daten in Datenbank ändern
- Teil 8: SQLite Datenbank Upgrade
Nun wünschen wir euch viel Spaß bei dem zweiten Teil unseres Android SQLite Datenbank Tutorials. Los geht’s!
1. Was ist das SQLite Datenbanksystem und wie ist SQLite in das Android System integriert?
SQLite ist eine Programmbibliothek, welche ein relationales Datenbanksystem enthält.
Das Open Source Datenbanksystem unterstützt eine Vielzahl der SQL-Sprachbefehle und wurde vor allem für den Einsatz in eingebetteten Umgebungen entworfen.
Besonders häufig wird das Datenbanksystem SQLite auf Betriebssystemen für Smartphones und Tablets eingesetzt, bspw. Symbian OS oder Android.
Der große Vorteil des SQLite Datenbanksystems ist der minimale Aufbau der Bibliothek.
Die gesamte SQLite-Bibliothek ist nur einige hundert Kilobyte groß und lässt sich direkt in die Android Anwendung integrieren. Es wird keine weitere Server-Software benötigt.
Durch das Einbinden der SQLite-Bibliothek wird eine Android App um sehr nützliche Datenbankfunktionen erweitert, ohne auf externe Software angewiesen zu sein.
Die SQLite-Datenbank besteht aus einer einzigen Datei, die alle Tabellen, Indizes usw. enthält.
Für die Kommunikation mit dem Datenbanksystem wird die spezielle Kommandosprache SQL verwendet, mit der folgende Operationen durchgeführt werden können:
- Definition der Tabellenstruktur
- Anlegen und Löschen von Tabellen
- Einfügen, Ändern und Löschen von Datensätzen, die eigentlich Tabellenzeilen sind
- Suchen von Daten aus einer oder mehreren Tabellen mit Hilfe von Suchkriterien
SQLite unterstützt die drei Datentypen TEXT
, INTEGER
und REAL
. In Java würden diese Datentypen den Typen String, Long bzw. Double am ehesten entsprechen. Alle anderen Datentypen müssen in einen dieser drei Typen konvertiert werden, bevor sie in der Datenbank abgespeichert werden können.
Weiterhin prüft SQLite nicht, ob der Datentyp des zu speichernden Eintrags tatsächlich dem Datentyp der zugewiesenen Spalte entspricht. SQLite erzwingt somit keine Typsicherheit. Fehlerhafte Eingaben werden in der Regel akzeptiert und in Zeichenketten umgewandelt.
Weitere Informationen über SQLite findet ihr an folgenden Stellen im Internet:
- SQLite Homepage
- SQLite bei Wikipedia.org
- SQLite-Package von Android
- SQL (Structured Query Language) bei Wikipedia.org
1.1 Was ist eine relationale Datenbank?
Eine Datenbank im Allgemeinen ist ein Konstrukt zum Ablegen von Daten. Die Daten werden in Tabellen abgelegt und organisiert. Eine Tabelle besteht aus einer vorgegebenen Anzahl an Spalten und Zeilen.
Die Daten verschiedener Tabellen können sich gegenseitig referenzieren und dadurch Beziehungen (Relationen) aufweisen. Dann haben wir es mit relationalen Datenbanken zu tun.
In den beiden unten aufgeführten Tabellen sind Benutzer- und Rechnungsdaten abgelegt und organisiert. Jede Zeile einer Tabelle bildet einen sog. Datensatz und setzt sich aus den Werten mehrerer Spalten (Felder) zusammen.
User-ID | Benutzername |
---|---|
1 | Fred The Red |
2 | Fritzle |
3 | Brian The Lion |
4 | Attila |
Rechnungs-Nr | Betrag | Status | User-ID |
---|---|---|---|
2308 | 120 € | offen | 3 |
2309 | 79 € | offen | 3 |
2310 | 10 € | bezahlt | 2 |
2311 | 199 € | offen | 4 |
Beide Tabellen besitzen jeweils eine Spalte, deren Werte innerhalb der Tabelle eindeutig sind. In den Spalten User-ID bzw. Rechnungs-Nr. gleicht kein Wert dem anderen, sie werden als Primärschlüssel bezeichnet.
In der rechten Tabelle (Rechnungsdaten) wird neben der Primärschlüssel-Spalte Rechnungs-Nr.
zusätzlich die Primärschlüssel-Spalte User-ID
der linken Tabelle verwendet. In diesem Fall spricht man von einem Fremdschlüssel. Somit wird die Spalte User-ID
als Fremdschlüssel-Spalte in der Tabelle Rechnungsdaten verwendet.
Über den Fremdschlüssel kann eine Verbindung von einem Datensatz einer Tabelle zu einem anderen Datensatz einer anderen Tabelle hergestellt werden. So kann über den Fremdschlüssel von der Tabelle Rechnungsdaten auf die Datensätze der Tabelle Benutzerdaten verwiesen werden.
1.2 Wie ist das SQLite Datenbanksystem in Android integriert
In Android ist das SQLite Datenbanksystem fester Bestandteil der Laufzeitumgebung. Dadurch kann jede Android App sehr einfach und effizient Daten in Form einer Datenbank ablegen und auslesen.
Das Einrichten und die Administration der Datenbank wird von Android übernommen. Wir müssen nur mit Hilfe von SQL-Anweisungen die Datenbank anlegen und updaten. Anschließend wird die Datenbank automatisch vom Android System verwaltet.
Die Klassen, die für das Einbinden einer SQLite-Datenbank in einer Android App benötigt werden, sind in dem Package android.database.sqlite zusammengefasst. Wir werden in diesem Android SQLite Tutorial die Klasse SQLiteOpenHelper verwenden und dabei näher kennenlernen.
Wenn wir in unserer Android App eine Datenbank erzeugen, wird diese standardmäßig in dem Verzeichnis DATA/data/PACKAGE_NAME/databases/FILENAME/ angelegt. Dabei sind die folgenden drei Platzhalter variabel:
- DATA – ist der Pfad der App-Umgebung, kann mit
Environment.getDataDirectory()
ausgegeben werden. - PACKAGE_NAME – ist der Name des Packages unserer Android Anwendung.
- FILENAME – ist der Dateiname der Datenbank, den wir in unserem Code vorgeben.
Der Pfad zu unserer Datenbank wird folgendermaßen aussehen:
/data/data/de.codeyourapp.shoppinglist/databases/shopping_list.db
2. Einsatz der SQLite Datenbank in unserer Android App
Es gibt verschiedene Wege eine SQLite-Datenbank in einer Android App zu verwenden. Dabei besitzt jeder Ansatz seine eigenen Vor- und auch Nachteile.
Wir wählen für dieses SQLite Tutorial den Mittelweg, der einen einfachen und übersichtlichen Zugriff auf die SQLite Datenbank ermöglicht, dabei aber nicht zu komplex ist.
Für unseren Ansatz werden wir drei Klassen verwenden, die im gemeinsamen Zusammenspiel das Speichern und Auslesen von Daten aus der SQLite-Datenbank übernehmen.
Die drei Java-Klassen werden wir jeweils in einem eigenen Abschnitt ausführlich vorstellen. In diesem Abschnitt stehen die Beziehungen der drei Klassen untereinander im besonderen Fokus.
In der unteren Liste sind die drei benötigten Klassen aufgeführt:
-
ShoppingMemo – Instanzen dieser Klasse können die Daten eines SQLite-Datensatzes aufnehmen. Sie repräsentieren die Datensätze im Code. Wir werden mit Objekten dieser Klasse den ListView füllen.
-
ShoppingMemoDbHelper – Sie ist eine Hilfsklasse mit deren Hilfe wir die SQLite-Datenbank erstellen lassen. Sie enthält weiterhin wichtige Konstanten, die wir für die Arbeit mit der Datenbank benötigen, wie den Tabellennamen, die Datenbankversion oder die Namen der Spalten.
-
ShoppingMemoDataSource – Diese Klasse ist unser Data Access Object und für das Verwalten der Daten verantwortlich. Es unterhält die Datenbankverbindung und ist für das Hinzufügen, Auslesen und Löschen von Datensätzen zuständig. Außerdem wandelt es Datensätze in Java-Objekte für uns um, so dass der Code unserer Benutzeroberfläche nicht direkt mit den Datensätzen arbeiten muss.
Wie aus den Beschreibungen zu den drei Klassen schon hervorgeht, ist jede Klasse auf die andere angewiesen. Die Grundlage bildet die Klasse ShoppingMemo, die wir für das Arbeiten mit den Datensätzen verwenden. Sie ist sozusagen das Datenobjekt und einem Datensatz unserer Datenbank nachgebildet.
Unsere Arbeiterklasse ist die ShoppingMemoDataSource-Klasse, die alle Verwaltungsaufgaben an der Datenbank übernimmt. Sie lässt mit Hilfe der Helper-Klasse die Datenbank erzeugen und hält die Verbindung zur Datenbank aufrecht. Durch sie können wir auf die Datensätze der Tabelle in unserer Datenbank zugreifen und diese verändern. Sie ist unser Zugriff auf die Daten, eben ein Data Access Object (DAO).
Alle wichtigen, konstanten Informationen über unsere Datenbank, wie Tabellenname, Versionsnummer, Spaltennamen oder SQL-Befehle sind in der Hilfsklasse ShoppingMemoDbHelper gesammelt. Sie ist von der Klasse SQLiteOpenHelper abgeleitet und kann daher eine Datenbank erzeugen.
Mit der DAO-Klasse ShoppingMemoDataSource nutzen wir die Helper-Klasse und lassen uns über sie eine Datenbank erzeugen und auch wieder schließen.
Steuern werden wir die ganzen Datenbankzugriffe von der MainActivity aus, die eine Instanz der ShoppingMemoDataSource-Klasse besitzen wird. Somit müssen wir dem Data Access Object nur mitteilen welche Operationen an der Datenbank ausgeführt werden sollen.
Die tatsächliche Durchführung übernimmt dann das DAO für uns.
In der unteren Abbildung sind die vier Klassen unserer Android SQLite-App dargestellt. Die Darstellung entspricht keiner Norm, sie zeigt einfach nur die Beziehungen der einzelnen Klassen zueinander.
In der Abbildung entspricht die Klasse DataSource unserer Klasse ShoppingMemoDataSource, die Klasse DbHelper entspricht ShoppingMemoDbHelper und die Klasse DataObject entspricht ShoppingMemo. Die unterschiedlichen Klassennamen wurden aus Platzgründen gewählt.
In den nächsten Abschnitten werden wir die drei zu erstellenden Klassen genauer vorstellen. Dabei gehen wir auch auf die speziellen Aufgaben ein, welche die jeweilige Klasse bei der Integration der SQLite Datenbank in unsere Android App übernimmt.
3. Die Klasse ShoppingMemo – Mit ihr repräsentieren wir die Datensätze unserer SQLite Datenbank
Wir werden nun die Klasse ShoppingMemo in unserem Android Studio Projekt neu anlegen.
Diese Klasse entspricht den Datensätzen in der Tabelle unserer SQLite Datenbank. Jeder Datensatz besteht aus einer eindeutigen id
, dem Namen des Produkts product
und der benötigten Menge quantity
.
Diesen Datensatz-Aufbau werden wir mit der neuen Klasse ShoppingMemo nachbilden, so dass Instanzen dieser Klasse die Daten eines SQLite-Datensatzes in sich aufnehmen können.
Um die Datenmodell-Klasse ShoppingMemo anzulegen, muss eine neue Java Klassendatei in dem Package-Ordner unseres Projekts erstellt werden. Dafür gibt es zwei Vorgehensweisen: über die obere Menüleiste oder über den Package-Ordner in der Project-Ansicht. Wir werden den zweiten Weg wählen, da er intuitiver und weniger fehleranfällig ist.
Als Erstes muss dafür die Project-Ansicht unseres Projekts so aufgeklappt werden, dass der Package-Ordner sichtbar wird. In diesen Package-Ordner werden wir nun die neue Klassendatei mit Hilfe des Create New Class-Dialog von Android Studio anlegen lassen.
Die Klassendatei ShoppingMemo.java
unseres Datenmodells legen wir nun folgendermaßen an:
- Mit der rechten Maustaste auf den Package-Ordner de.codeyourapp.shoppinglist klicken.
- Anschließend den Eintrag New des Kontext-Menüs anklicken.
- Danach auf den Eintrag Java Class klicken.
Anschließend öffnet sich der Create New Class-Dialog, der uns bei der Erstellung der neuen Java Klasse unterstützt. Wir müssen nur einige Felder des Dialogs ausfüllen.
In dem Create New Class-Dialog nehmen wir nun die folgenden Einstellungen vor:
- Als Klassennamen tragen wir in das Feld Name ShoppingMemo ein.
- Den Wert für Kind lassen wir auf Class stehen.
- Die Felder Superclass und Interface(s) lassen wir leer.
- Als Package sollte bereits automatisch unser Package-Ordner de.codeyourapp.shoppinglist eingetragen sein.
- Alle anderen Einstellungen übernehmen wir unverändert.
- Den Dialog bestätigen wir mit einem Klick auf den OK Button.
Android Studio legt nun automatisch die neue Java Klasse an. Dabei wird auch der minimale Quellcode für das Klassengerüst erzeugt. Diesen benötigen wir aber nicht und werden ihn daher vollständig durch unseren eigenen Code ersetzen.
Im Editorfenster ersetzen wir nun den gesamten Quelltext der ShoppingMemo.java
mit folgendem Code:
ShoppingMemo.java
package de.codeyourapp.shoppinglist; public class ShoppingMemo { private String product; private int quantity; private long id; public ShoppingMemo(String product, int quantity, long id) { this.product = product; this.quantity = quantity; this.id = id; } public String getProduct() { return product; } public void setProduct(String product) { this.product = product; } public int getQuantity() { return quantity; } public void setQuantity(int quantity) { this.quantity = quantity; } public long getId() { return id; } public void setId(long id) { this.id = id; } @Override public String toString() { String output = quantity + " x " + product; return output; } }
Die ShoppingMemo-Klasse besitzt die drei Membervariablen product
, quantity
und id
, auf die mit Hilfe der get– und set-Methoden zugegriffen werden kann.
Mit dem Konstruktor können wir die ShoppingMemo-Objekte erzeugen lassen. Die drei Instanzvariablen product
, quantity
und id
werden beim Erzeugen der Objekte direkt mit den übergebenen Werten gefüllt.
Später werden wir die ShoppingMemo-Klasse nutzen, um die Daten der Datensätze unserer SQLite-Datenbank in Java-Objekten zu speichern. Diese Objekte entsprechen dann exakt einem Datensatz. Wir können dann mit den Objekten in unserem Code weiterarbeiten und ihren Inhalt bequem in einer Liste, bspw. mit Hilfe eines ListViews, ausgeben.
Ihren Inhalt können wir auch verändern und später die Änderungen in dem korrespondierenden Datensatz mit Hilfe der Objekte vornehmen. Die Klasse ShoppingMemo hilft uns somit Ordnung in das Datenchaos zu bringen und ermöglicht einen sichereren Umgang mit der SQLite-Datenbank.
In Android Studio sollte die eben erstellte Klasse ShoppingMemo.java
jetzt folgendermaßen aussehen:
In der oberen Abbildung ist die Klasse ShoppingMemo im Editor von Android Studio bereits geöffnet. Der weiter oben aufgeführte Quellcode wurde schon eingefügt. Außerdem ist auch der Speicherort ihrer Klassendatei im Project Tool Window zu sehen.
4. Die Klasse ShoppingMemoDbHelper – Unsere Hilfsklasse für das Erzeugen der SQLite Datenbank
In diesem Arbeitsschritt werden wir eine weitere neue Java-Klasse in Android Studio anlegen. Die neue Klasse ShoppingMemoDbHelper wird uns bei dem Erzeugen und Updaten der SQLite Datenbank unterstützen.
Wie ihr Name schon andeutet, ist sie eine Hilfsklasse, die wir nicht zwingend benötigen. Sie vereinfacht aber die Arbeit mit der SQLite Datenbank sehr stark.
Die Hilfsklasse leiten wir von der Klasse SQLiteOpenHelper aus dem Package android.database.sqlite
ab. Diese Elternklasse wird das eigentliche Erzeugen der SQLite Datenbank für uns übernehmen. Wir delegieren dies nur mit unserer Hilfsklasse ShoppingMemoDbHelper an sie weiter.
Die Klassendatei ShoppingMemoDbHelper.java
legen wir nun, wie schon im vorherigen Abschnitt beschrieben, an:
- Mit der rechten Maustaste auf den Package-Ordner de.codeyourapp.shoppinglist klicken.
- Anschließend den Eintrag New des Kontext-Menüs anklicken.
- Danach auf den Eintrag Java Class klicken.
Es öffnet sich wieder der Create New Class-Dialog, der uns bei der Erstellung der neuen Java Klasse unterstützt. Wir müssen nur einige Felder des Dialogs ausfüllen.
In dem Create New Class-Dialog nehmen wir nun die folgenden Einstellungen vor:
- Als Klassennamen tragen wir in das Feld Name ShoppingMemoDbHelper ein.
- Den Wert für Kind lassen wir auf Class stehen.
- Die Felder Superclass und Interface(s) lassen wir leer.
- Als Package sollte bereits automatisch unser Package-Ordner de.codeyourapp.shoppinglist eingetragen sein.
- Alle anderen Einstellungen übernehmen wir unverändert.
- Den Dialog bestätigen wir mit einem Klick auf den OK Button.
Android Studio legt nun automatisch die neue Java Klasse ShoppingMemoDbHelper an. Sie wird im Package-Ordner unseres Android Projekts abgelegt, worin sich auch die MainActivity und ShoppingMemo Klassen befinden.
Im Editorfenster ersetzen wir nun den gesamten Quelltext der ShoppingMemoDbHelper.java
mit folgendem Code:
ShoppingMemoDbHelper.java
package de.codeyourapp.shoppinglist; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; public class ShoppingMemoDbHelper extends SQLiteOpenHelper{ private static final String LOG_TAG = ShoppingMemoDbHelper.class.getSimpleName(); public ShoppingMemoDbHelper(Context context) { super(context, "PLATZHALTER_DATENBANKNAME", null, 1); Log.d(LOG_TAG, "DbHelper hat die Datenbank: " + getDatabaseName() + " erzeugt."); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
In dem oberen Quelltext passiert noch nicht viel. Wir sehen das minimale Grundgerüst unserer Hilfsklasse und die notwendigen Import-Anweisungen.
Da sich unsere Klasse von der SQLiteOpenHelper-Klasse ableitet, müssen wir deren beiden abstrakten Methoden onCreate() und onUpgrade() implementieren.
Mit dem Aufruf des Konstruktors der Elternklasse in Zeile 14 geben wir die wichtigen Daten für das Erzeugen der SQLite Datenbank an die SQLiteOpenHelper-Klasse weiter. Dabei enthält der context
die Informationen über die Umgebung, in der die Datenbank ausgeführt wird, wie bspw. der Pfad zur Datenbank.
Den Datenbanknamen werden wir später in einer String-Konstante angeben, daher arbeiten wir hier mit einem Platzhalter. Das letzte Argument gibt die Version unserer Datenbank an. Bei jedem Datenbank-Upgrade wird dieser Wert um eins erhöht.
In Android Studio sollte die eben erstellte Klasse ShoppingMemoDbHelper jetzt folgendermaßen aussehen:
Wie das Erzeugen der SQLite Datenbank erfolgt, werden wir im nächsten Teil des Tutorials ausführlich beschreiben. Dann wird die Klasse ShoppingMemoDbHelper vervollständigt werden.
Für den Moment ist das minimale Grundgerüst aber ausreichend, so dass wir nun zur dritten und letzten neuen Java-Klasse unserer Android SQLite-App kommen.
5. Die Klasse ShoppingMemoDataSource – Unsere Arbeiterklasse, sie regelt die SQLite Datenbankzugriffe
Kommen wir nun zu unserer Arbeiterklasse ShoppingMemoDataSource. Sie ist für alle Datenbankzugriffe verantwortlich. Mit ihrer Hilfe schreiben wir Datensätze in die Tabelle unserer SQLite Datenbank und lesen diese auch wieder aus.
Die ShoppingMemoDataSource-Klasse besitzt eine Membervariable vom Datentyp SQLiteDatabase, in der wir unsere Datenbank-Objekte abspeichern werden. Dadurch hält die ShoppingMemoDataSource-Klasse die Verbindung zu unserer Datenbank aufrecht.
Weiterhin besitzt sie eine Membervariable vom Typ ShoppingMemoDbHelper, mit deren Hilfe wir die SQLite Datenbank erstellen lassen bzw. die Verbindung zur Datenbank herstellen können, wenn bereits eine Datenbank angelegt wurde.
Außerdem wird die Arbeiterklasse weitere Funktionen zur Verfügung stellen, die das Arbeiten mit den Datensätzen erleichtern. Dazu werden wir in späteren Teilen dieses SQLite Tutorials ausführlich eingehen.
Nun wollen wir die Klasse ShoppingMemoDataSource.java
anlegen. Wie schon in den vorherigen Abschnitten beschrieben, legen wir die neue Java-Klasse folgendermaßen an:
- Mit der rechten Maustaste auf den Package-Ordner de.codeyourapp.shoppinglist klicken.
- Anschließend den Eintrag New des Kontext-Menüs anklicken.
- Danach auf den Eintrag Java Class klicken.
Es öffnet sich wieder der Create New Class-Dialog, der uns bei der Erstellung der neuen Java Klasse unterstützt. Wir müssen nur einige Felder des Dialogs ausfüllen.
In dem Create New Class-Dialog nehmen wir nun die folgenden Einstellungen vor:
- Als Klassennamen tragen wir in das Feld Name ShoppingMemoDataSource ein.
- Den Wert für Kind lassen wir auf Class stehen.
- Die Felder Superclass und Interface(s) lassen wir leer.
- Als Package sollte bereits automatisch unser Package-Ordner de.codeyourapp.shoppinglist eingetragen sein.
- Alle anderen Einstellungen übernehmen wir unverändert.
- Den Dialog bestätigen wir mit einem Klick auf den OK Button.
Android Studio legt nun automatisch die neue Java Klasse ShoppingMemoDataSource an. Sie wird im Package-Ordner unseres Android Projekts abgelegt, worin sich alle von uns erstellten Klassen befinden.
Im Editorfenster ersetzen wir nun den gesamten Quelltext der ShoppingMemoDataSource.java
mit folgendem Code:
ShoppingMemoDataSource.java
package de.codeyourapp.shoppinglist; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.util.Log; public class ShoppingMemoDataSource { private static final String LOG_TAG = ShoppingMemoDataSource.class.getSimpleName(); private SQLiteDatabase database; private ShoppingMemoDbHelper dbHelper; public ShoppingMemoDataSource(Context context) { Log.d(LOG_TAG, "Unsere DataSource erzeugt jetzt den dbHelper."); dbHelper = new ShoppingMemoDbHelper(context); } }
Die Klasse ShoppingMemoDataSource besteht momentan nur aus den beiden Membervariablen database
und dbHelper
, sowie aus dem Konstruktor ShoppingMemoDataSource(Context context).
In dem Konstruktor erzeugen wir eine ShoppingMemoDbHelper-Instanz und übergeben ihr den Context, also die Umgebung in der unsere App ausgeführt wird. Mit Hilfe der erzeugten Instanz dbHelper
werden wir später die Verbindung zu unserer SQLite Datenbank herstellen.
Hinweis: Es gibt zwei Arten von Context-Objekten: den Applictaion Context (getApplicationContext()) und den Activity Context. Wir übergeben als Context den Activity Context in Form einer Referenz auf unsere MainActivity-Instanz, von welcher das ShoppingMemoDataSource-Objekt erzeugt wird.
Mehr gibt es im Moment zu dem Quellcode der Klasse ShoppingMemoDataSource nicht zu sagen. Auch diese Klasse wird mit dem SQLite Tutorial mitwachsen und Lektion für Lektion weiter vervollständigt werden.
In Android Studio sollte die eben erstellte Klasse ShoppingMemoDataSource nun folgendermaßen aussehen:
Jetzt haben wir die drei benötigten Klassen angelegt und mit Quellcode befüllt. Als Nächstes sollten wir unsere Android App ausführen und testen, ob alle Arbeitsschritte korrekt durchgeführt wurden.
Wir werden dazu etwas Testcode in der MainActivity-Klasse ergänzen und anschließend unsere App auf einem Android Gerät ausführen.
6. Einfügen des Testcodes in die MainActivity der SQLite App
Jetzt sind wir fast am Ende vom zweiten Teil des Android SQLite Tutorials angekommen. Wir haben in dieser Lektion drei neue Java-Klassen erstellt, mit deren Hilfe wir in den späteren Teilen des Tutorials auf die SQLite Datenbank zugreifen werden.
Doch bevor wir mit der Datenbank arbeiten können, müssen wir sicherstellen, dass die drei neuen Klassen korrekt funktionieren.
Um dies zu testen, öffnen wir die Klassendatei MainActivity.java
im Editor von Android Studio, indem wir doppelt auf ihren Dateinamen im Project Tool Window klicken. Die Klassendatei befindet sich im Package-Ordner de.codeyourapp.shoppinglist unseres Projekts.
Ihren bisherigen Quellcode lassen wir zu großen Teilen bestehen und fügen nur einige neue Zeilen darin ein. Der bereits überarbeitet Quellcode der MainActivity.java
ist unten aufgeführt:
MainActivity.java
package de.codeyourapp.shoppinglist; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; public class MainActivity extends AppCompatActivity { public static final String LOG_TAG = MainActivity.class.getSimpleName(); private ShoppingMemoDataSource dataSource; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ShoppingMemo testMemo = new ShoppingMemo("Birnen", 5, 102); Log.d(LOG_TAG, "Inhalt der Testmemo: " + testMemo.toString()); dataSource = new ShoppingMemoDataSource(this); } }
In Zeile 5 importieren wir die Log-Klasse und machen sie dadurch innerhalb unserer eigenen Klasse sichtbar. Anschließend legen wir in Zeile 10 die Konstante LOG_TAG
an und speichern in ihr den Namen unserer Klasse. So können wir später im Logcat Tool Window von Android Studio direkt erkennen, wenn eine Log-Meldung von der MainActivity-Klasse ausgegeben wird.
In Zeile 12 legen wir die Membervariable dataSource
an. In ihr werden wir eine Referenz auf das ShoppingMemoDataSource-Objekt speichern, wodurch unsere MainActivity-Klasse immer eine Verbindung zum Data Access Object der Datenbank aufrecht hält.
Anschließend überprüfen wir die Funktion unserer drei erstellten Klassen:
-
Testen der ShoppingMemo-Klasse – In Zeile 19 erzeugen wir die ShoppingMemo-Instanz
testMemo
und geben ihren Inhalt mit der Log-Anweisung in Zeile 20 an die Konsole aus. -
Testen der beiden anderen Klassen – In Zeile 22 erzeugen wir ein ShoppingMemoDataSource-Objekt. Dadurch werden die beiden Konstruktoren der Klassen ShoppingMemoDataSource und ShoppingMemoDbHelper der Reihe nach aufgerufen und die darin angegebenen Log-Meldungen ausgegeben.
Auf diese Weise können wir prüfen, ob die drei Klassen richtig angelegt wurden. Diese Tests sind keine Funktionstests und garantieren auch nicht die Korrektheit unseres Quellcodes. Wir können aber mit diesen Tests schnell herausfinden, ob etwas beim Befolgen der Arbeitsschritte fehlgeschlagen ist. Mehr dazu im nächsten Abschnitt.
Die MainActivity.java
Datei sollte in Android Studio nun wie folgt aussehen:
Nachdem wir nun den Testcode in die MainActivity eingefügt haben, können wir die Funktion unserer Anwendung überprüfen. Dazu werden wir in den beiden nächsten Unterabschnitten unsere Android SQLite App auf einem virtuellen Android Gerät ausführen und die Log-Meldungen im Logcat Tool Window von Android Studio überprüfen.
Wenn ihr die gleichen Log-Meldungen erhaltet, sollte das Anlegen der drei Klassen auch bei euch erfolgreich verlaufen sein.
7. Ausführen und Überprüfen unserer Android SQLite App
Wir werden nun unserer Android App auf einem Android Virtual Device im Emulator ausführen lassen und die Log-Meldungen unserer Anwendung im Logcat Tool Window überprüfen. Auf diese Weise können wir das Verhalten der eben erstellten Klassen direkt in Android Studio analysieren.
Hinweis: Wenn ihr Probleme beim Ausführen der App im Android Emulator oder auf einem Android Gerät haben solltet, könnt ihr unseren großen Android Apps Programmieren Kurs als Hilfe nutzen. Darin zeigen wir, wie eine Android App im Emulator oder auf einem physikalischen Android Gerät ausgeführt wird.
Unsere App starten wir dazu wie gewohnt über den Run > Run 'app' Menüeintrag, den wir über die obere Menüleiste erreichen.
Unsere SQLite App sollte jetzt auf dem Android Gerät gestartet worden sein. Die grafische Benutzeroberfläche der Anwendung hat sich nicht geändert, daher sieht auf dem Gerät alles genau so aus wie in der vorherigen Lektion.
Hinweis: Das Emulator-Fenster mit dem darin laufenden Android Virtual Device muss für die nächsten Arbeitsschritte geöffnet bleiben. Zudem muss in dem AVD unsere eigene App ausgeführt werden. Sollte dies nicht der Fall sein, muss die App erneut im Emulator gestartet werden.
Um die Log-Meldungen zu überprüfen, öffnen wir in Android Studio das Logcat Tool Window während unsere App auf dem AVD im Emulator ausgeführt wird.
Dazu führen wir die folgenden Schritte aus:
- Wir öffnen das Logcat Tool Window mit einem Klick auf den Logcat-Tab am unteren Bildschirmrand.
- Anschließend wählen wir Emulator Nexus_9 als AVD in der Drop-Down Liste aus.
- Nun wählen wir unsere App de.codeyourapp.shoppinglist in der Liste rechts daneben aus.
- Danach stellen wir die Prioritätsstufe auf Verbose ein.
- Und geben in das anschließende Suchfeld MainActivity|ShoppingMemo als Suchbegriff ein.
- Zuletzt wählen wir den Eintrag Show only selected application in Liste ganz rechts aus.
Mit den getätigten Einstellungen werden nun alle von unserer Anwendung ausgehenden Log-Meldungen im Logcat Tool Window ausgegeben. Wie in der oberen Abbildung zu erkennen ist, sind dies genau drei Log-Meldungen.
Zuerst teilt die MainActivity-Klasse den Inhalt der erzeugten Testmemo mit. Anschließend informiert die ShoppingMemoDataSource-Klasse darüber, dass sie nun das dbHelper-Objekt erzeugt. Woraufhin die ShoppingMemoDbHelper-Klasse uns über das Erzeugen einer Test-Datenbank informiert.
Wenn auch bei euch diese drei Log-Meldungen ausgegeben werden, hat das Erstellen der neuen Java-Klassen ordnungsgemäß funktioniert. Somit haben wir den Grundstein für unsere SQLite Datenbank Anwendung gelegt.
In den nächsten Lektionen werden wir mit den erstellten Klassen weiterarbeiten und über sie auf die SQLite Datenbank zugreifen. Dabei werdet ihr auch besser nachvollziehen können, warum wir diese Vorgehensweise gewählt haben und welche Vorteile beim Arbeiten mit dem Datenbanksystem dadurch entstehen.
Zusammenfassung
In dieser, doch etwas längeren, Lektion des Android SQLite Tutorials haben wir das Fundament für unsere Datenbank Anwendung gelegt. Die Android App macht momentan noch nichts, ist aber jetzt schon in der Lage eine SQLite Datenbank zu erzeugen.
Dies haben wir erreicht, indem wir drei neue Klassen mit Hilfe von Android Studio angelegt und diese mit Quellcode befüllt haben. Jede der drei Java-Klassen übernimmt dabei eine bestimmte Aufgabe.
Die ShoppingMemo-Klasse repräsentiert die Datensätze unserer SQLite Datenbank. Die ShoppingMemoDbHelper-Klasse hilft uns beim Erstellen und Aktualisieren der Datenbank. Die eigentliche Arbeit wird von der ShoppingMemoDataSource-Klasse übernommen, sie regelt alle Datenbankzugriffe, ob lesend oder schreibend, für unsere App.
Vor dem Anlegen der neuen Klassen haben wir das SQLite Datenbanksystem näher kennengelernt und erfahren, wie SQLite in der Android Plattform integriert ist. Danach haben wir den Ansatz vorgestellt, der beschreibt, wie wir die SQLite Datenbank in unserer Android App einsetzen wollen.
Am Ende der Lektion haben wir die MainActivity-Klasse mit Testcode erweitert und dadurch überprüft, ob alle drei Klassen korrekt angelegt wurden.
Nun sind wir bereit für den nächsten Schritt auf dem Weg hin zu einer funktionsfähigen Android SQLite Anwendung. In der nächsten Lektion werden wir eine Tabelle in unserer SQLite Datenbank anlegen und dabei SQL-Queries näher kennenlernen.
Comments 18
Hallo Chris,
erstmal auch von mir ein dickes Lob für das Tutorial. Mir gefällt vor allem, dass du auch auf die Hintergründe eingehst.
Mein Problem:
Ich kann im LogCat-Fenster unter Punkt 3 nichts einstellen. Bei mir steht „No debuggable processes“ in rot in der Zeile. Das Dropdown-Menu ist leer.
Ich benutze keinen Emulator, sondern mein Samsung Galaxy S8 als physikalisches Gerät. Die App wird auch geöffnet. Ich finde nur leider in der LogCat kein „de.codeyourapp.shoppinglist“-package.
Grüße
Florian
Author
Hallo Florian,
danke für dein Lob!
Ich habe selbst ein Galaxy S8 und damit alle meine Lektionen getestet. Es hat problemlos funktioniert. Daher sollte es mit deinem Handy klappen.
Ich denke zwar, dass du die folgenden Schritte alle befolgt hast, aber ich führe sie zur Übersicht einmal auf:
Das ist alles. Mit diesen Schritten sollten auch bei Dir die Logcat-Meldungen vom Handy in Android Studio ausgegeben werden. Mehr ist nicht zu tun. Hast du einen Viren-Scanner? Manchmal machen Anti-Viren Programme Probleme mit Android Studio.
Sobald es Dir möglich ist die App auf das Handy mittels Run App zu übertragen, besteht ja eine funktionierende USB-Verbindung über die Android Debug Bridge. Somit sollten dann auch die Log-Meldungen darüber übertragen werden können.
Ich hoffe, meine Aufführungen helfen Dir etwas weiter.
Viele Grüße, Chris
Hallo Chris,
super Tutorial!
Ich nutze das als Referenz für mein eigenes Projekt. Dabei habe ich eine Datenbank mit 3 Tabellen.
Dadurch, dass hier in der Klasse die toString() Methode überschrieben ist, werden in den Ausgaben natürlich immer nur die Strings richtig angezeigt, die auch über toString() angefragt werden. Für alle anderen kommt ein Text wie bei Tobias:
Hast du eine Idee / einen Vorschlag, wie man das fixen kann?
Viele Grüße!
Author
Hallo Pascal,
wenn jede deiner Tabelle ein eigenes Datenmodell, hier im Tutorial die ShoppingMemo-Klasse, verwendet, muss für die entsprechenden Datenmodell-Klassen die toString() Methode implementiert werden.
Viele Grüße, Chris
Hi,
echt ein super Tutorial! Hilfreich ist es, dass auch viele Schritte immer wiederholt werden.
Allerdings stoße ich am Ende auf ein Problem wenn ich die App testen will. Ich bekomme folgende Fehlermeldung:
Sorry bin blutiger Anfänger und kann nicht erkennen, dass ich etwas falsch gemacht habe.
Wäre super wenn mir jemand weiterhelfen kann!
Gruß
Peter
Author
Hallo Peter,
danke für dein Lob! Anhand der Fehlermeldung ist in deinem Quellcode die onCreate() Methode zweimal vorhanden. Die Methode darf aber nur einmal existieren.
Viele Grüße, Chris
Hallo,
mir gefällt das Tutorial echt gut, es ist sehr angenehm geschrieben, Danke!
Leider möchte bei mir in der Helper Klasse einiges nicht.
1. die super Funktion nicht und gibt mir auch keine Gründe warum.
2. Er nutzt den Import der SQLiteOpenHelper nicht.
3. Die Overrides sagen mir, dass sie nicht Overriden
Wäre schön, wenn jemand Ideen hat woran es liegt
Author
Hallo Avo,
danke für dein Lob!
Schwer zu sagen, woran es liegt. Wenn du möchtest, kannst Du mir deine Projektdateien (den ganzen Android Studio Projektordner) als ZIP per E-Mail zusenden. Die E-Mail Adresse kannst Du im Impressum finden. Ich schaue dann mal, ob ich etwas herausfinden kann. Sollte die Zip-Datei zu groß sein, dann schicke nur die Java Quellcode-Dateien.
Viele Grüße, Chris
Hallo,
wirkliche ein gelungenes Tutorial , das hat mir sehr geholfen!
Ich habe jedoch ein Problem, dass ich die Datenabnkeinträge nicht angezeigt bekomme. Bei mir zeigts in der Log nur eine Art Adresse an:
D/MainActivity: Inhalt der Testmemo:
com.example.tuttiadmin.knobel_statistik.KnobelMemo@1780e24
Also sind Einträge drin, aber ich kann die Daten so nicht sehen …
Author
Hallo Tobias,
danke für’s Lob!
Ist in deiner Klasse KnobelMemo die Methode toString() implementiert? Falls nicht, könnte das die Lösung sein.
Viele Grüße, Chris
Hallo Chris,
ja das wars 😀
Ich habe die Methoden automatisch angelegt und die String Methode total übersehen haha,
vielen Dank !
Hi, also ich habe da ein „kurioses“ Problem mit den Log Ausgaben. Ich lasse das Projekt auf einem Huawei Mate S laufen. Die App läuft dort Problemlos und ohne Fehlermeldung, jedoch übergibt sie keinerlei Daten an den logcat. Auf dem Device läuft Android 5.1.1, API 22.
Wenn ich das Projekt jetzt aber über den Emulator laufen lasse, dann wird die Log Ausgabe aber ausgegeben. Kann das an einer falschen ADB Anbindung zwischen dem Huawei liegen?!
Author
Hallo Rene,
ja, es kann schon an dem Zusammenspiel zwischen dem Huawei und Android Studio (bzw. der ADB) liegen. Es gab schon einmal eine Leserin, die über ein Problem mit ihrem Huawei berichtet hatte. Vielleicht ist auf Huawei-Geräten auch das Android Logging System etwas anders implementiert worden?
Viele Grüße, Chris
Sehr nützliches Tutorial, gut aufgebaut!
Vielen Dank
Author
Hallo Uli,
danke für das Lob! Es freut mich wenn das Tutorial nützlich ist und den Lesern hilft.
Viele Grüße, Chris
Ich habe den Code aus eurem Artikel mehrere Male kopiert und bekomme jedesmal nur 2 Meldungen im Log, die 1. („Inhalt der Testmemo: 5x Birnen“) wird mir nicht angezeigt.
Kann es sein, das dies an der Android Version, auf welche die App kompiliert wird (nicht die minimal Anforderung!) liegt?
Author
Hallo Jojo,
die erste Meldung (“Inhalt der Testmemo: 5x Birnen”) sollte auch bei dir auf jeden Fall angezeigt werden. Gerade da die anderen beiden Meldungen bei dir auch angezeigt werden. Eventuell liegt es an dem Log-Filter, da die erste Meldung von der MainActivity aus versendet wird. Versuche mal ohne Log-Filter die Meldungen zu betrachten oder nur Meldungen der MainActivity anzeigen zu lassen.
Ich hoffe das hilft dir weiter 🙂
Viele Grüße, Chris
Pingback: Android SQLite Tutorial - Teil 1: SQLite Projekt anlegen