Dieses Codelab ist Teil des Kurses „Grundlagen von Android und Kotlin“. Sie können diesen Kurs am besten nutzen, wenn Sie die Codelabs der Reihe nach durcharbeiten. Alle Codelabs des Kurses sind auf der Landingpage für Codelabs zu den Grundlagen von Android und Kotlin aufgeführt.
Einführung
Die meisten Apps haben Daten, die auch nach dem Schließen der App durch den Nutzer aufbewahrt werden müssen. Die App speichert beispielsweise eine Playlist, ein Inventar von Spielelementen, Aufzeichnungen von Ausgaben und Einnahmen, einen Katalog von Sternbildern oder Schlafdaten im Zeitverlauf. Normalerweise verwenden Sie eine Datenbank zum Speichern persistenter Daten.
Room ist eine Datenbankbibliothek, die Teil von Android Jetpack ist. Room übernimmt viele der Aufgaben, die mit dem Einrichten und Konfigurieren einer Datenbank verbunden sind, und ermöglicht es Ihrer App, über normale Funktionsaufrufe mit der Datenbank zu interagieren. Room ist eine Abstraktionsschicht über einer SQLite-Datenbank. Die Terminologie von Room und die Abfragesyntax für komplexere Abfragen folgen dem SQLite-Modell.
Das Bild unten zeigt, wie die Room-Datenbank in die in diesem Kurs empfohlene Gesamtarchitektur passt.

Was Sie bereits wissen sollten
Sie sollten mit Folgendem vertraut sein:
- Einfache Benutzeroberfläche für eine Android-App erstellen
- Aktivitäten, Fragmente und Ansichten verwenden
- Zwischen Fragmenten navigieren und Safe Args (ein Gradle-Plug-in) verwenden, um Daten zwischen Fragmenten zu übergeben.
- Modelle, Viewmodel-Factories,
LiveDataund seine Observer ansehen. Diese Themen zu Architecture Components werden in einem früheren Codelab in diesem Kurs behandelt. - Grundkenntnisse in SQL-Datenbanken und der SQLite-Sprache. Eine kurze Übersicht oder Auffrischung finden Sie im SQLite-Primer.
Lerninhalte
- So erstellen Sie eine
Room-Datenbank und interagieren mit ihr, um Daten zu speichern. - So erstellen Sie eine Datenklasse, die eine Tabelle in der Datenbank definiert.
- Verwendung eines Data Access Object (DAO) zum Zuordnen von Kotlin-Funktionen zu SQL-Abfragen.
- So testen Sie, ob Ihre Datenbank funktioniert.
Aufgaben
- Erstelle eine
Room-Datenbank mit einer Schnittstelle für Daten zum nächtlichen Schlaf. - Testen Sie die Datenbank mit den bereitgestellten Tests.
In diesem Codelab erstellen Sie den Datenbankteil einer App, die die Schlafqualität erfasst. Die App verwendet eine Datenbank, um Schlafdaten im Zeitverlauf zu speichern.
Die App hat zwei Bildschirme, die durch Fragmente dargestellt werden, wie in der Abbildung unten zu sehen ist.
Auf dem ersten Bildschirm links befinden sich Schaltflächen zum Starten und Beenden des Trackings. Auf dem Bildschirm werden alle Schlafdaten des Nutzers angezeigt. Mit der Schaltfläche Löschen werden alle Daten, die die App für den Nutzer erhoben hat, dauerhaft gelöscht.
Auf dem zweiten Bildschirm rechts können Sie eine Bewertung der Schlafqualität auswählen. In der App wird die Bewertung numerisch dargestellt. Zu Entwicklungszwecken werden in der App sowohl die Gesichtssymbole als auch ihre numerischen Entsprechungen angezeigt.
Der Ablauf für den Nutzer sieht so aus:
- Der Nutzer öffnet die App und sieht den Bildschirm für die Schlafanalyse.
- Der Nutzer tippt auf die Schaltfläche Starten. Die Startzeit wird aufgezeichnet und angezeigt. Die Schaltfläche Starten ist deaktiviert und die Schaltfläche Beenden ist aktiviert.
- Der Nutzer tippt auf die Schaltfläche Stopp. Dadurch wird die Endzeit aufgezeichnet und der Bildschirm „Schlafqualität“ geöffnet.
- Der Nutzer wählt ein Symbol für die Schlafqualität aus. Der Bildschirm wird geschlossen und auf dem Tracking-Bildschirm werden die Endzeit des Schlafs und die Schlafqualität angezeigt. Die Schaltfläche Beenden ist deaktiviert und die Schaltfläche Starten ist aktiviert. Die App ist bereit für eine weitere Nacht.
- Die Schaltfläche Löschen ist immer dann aktiviert, wenn Daten in der Datenbank vorhanden sind. Wenn der Nutzer auf die Schaltfläche Löschen tippt, werden alle seine Daten unwiderruflich gelöscht. Es wird keine Bestätigungsmeldung angezeigt.
Diese App verwendet eine vereinfachte Architektur, wie unten im Kontext der vollständigen Architektur dargestellt. Die App verwendet nur die folgenden Komponenten:
- UI-Controller
- Modell und
LiveDataansehen - Eine Room-Datenbank
Schritt 1: Start-App herunterladen und ausführen
- Laden Sie die App TrackMySleepQuality-Starter von GitHub herunter.
- Erstellen Sie die App und führen Sie sie aus. In der App wird die Benutzeroberfläche für das Fragment
SleepTrackerFragmentangezeigt, aber keine Daten. Die Tasten reagieren nicht auf Antippen.
Schritt 2: Startanwendung prüfen
- Sehen Sie sich die Gradle-Dateien an:
- Gradle-Datei des Projekts
: In derbuild.gradle-Datei auf Projektebene sehen Sie die Variablen, mit denen die Bibliotheksversionen angegeben werden. Die in der Starter-App verwendeten Versionen funktionieren gut zusammen und auch mit dieser App. Wenn Sie dieses Codelab abgeschlossen haben, werden Sie in Android Studio möglicherweise aufgefordert, einige der Versionen zu aktualisieren. Es liegt an Ihnen, ob Sie die Versionen in der App aktualisieren oder beibehalten möchten. Wenn Sie auf „seltsame“ Kompilierungsfehler stoßen, versuchen Sie es mit der Kombination von Bibliotheksversionen, die in der App mit der endgültigen Lösung verwendet werden. - Die Gradle-Datei des Moduls. Beachten Sie die bereitgestellten Abhängigkeiten für alle Android Jetpack-Bibliotheken, einschließlich
Room, und die Abhängigkeiten für Coroutines.
- Pakete und Benutzeroberfläche Die App ist nach Funktionen strukturiert. Das Paket enthält Platzhalterdateien, in die Sie im Laufe dieser Codelabs Code einfügen.
- Das Paket
databasefür den gesamten Code, der sich auf dieRoom-Datenbank bezieht. - Die Pakete
sleepqualityundsleeptrackerenthalten das Fragment, das View-Modell und die View-Modell-Factory für jeden Bildschirm.
- Sehen Sie sich die Datei
Util.ktan, die Funktionen zum Anzeigen von Daten zur Schlafqualität enthält. Einige Codezeilen sind auskommentiert, da sie auf ein View-Modell verweisen, das Sie später erstellen. - Sehen Sie sich den androidTest-Ordner (
SleepDatabaseTest.kt) an. Mit diesem Test können Sie prüfen, ob die Datenbank wie vorgesehen funktioniert.
Unter Android werden Daten in Datenklassen dargestellt. Der Zugriff auf die Daten und die Änderung der Daten erfolgt über Funktionsaufrufe. In der Welt der Datenbanken benötigen Sie jedoch Entitäten und Abfragen.
- Eine Entität stellt ein Objekt oder Konzept und seine Attribute dar, die in der Datenbank gespeichert werden sollen. Eine Entitätsklasse definiert eine Tabelle und jede Instanz dieser Klasse stellt eine Zeile in der Tabelle dar. Jede Eigenschaft definiert eine Spalte. In Ihrer App enthält die Entität Informationen zu einer Nacht Schlaf.
- Eine Abfrage ist eine Anfrage nach Daten oder Informationen aus einer Datenbanktabelle oder einer Kombination von Tabellen oder eine Anfrage zum Ausführen einer Aktion für die Daten. Häufige Anfragen sind das Abrufen, Einfügen und Aktualisieren von Entitäten. Du könntest beispielsweise alle aufgezeichneten Schlafnächte nach Startzeit sortiert abfragen.
Room übernimmt die ganze Arbeit für Sie, um von Kotlin-Datenklassen zu Entitäten zu gelangen, die in SQLite-Tabellen gespeichert werden können, und von Funktionsdeklarationen zu SQL-Abfragen.
Sie müssen jede Entität als annotierte Datenklasse und die Interaktionen als annotierte Schnittstelle, ein Data Access Object (DAO), definieren. Room verwendet diese annotierten Klassen, um Tabellen in der Datenbank und Abfragen zu erstellen, die auf die Datenbank zugreifen.

Schritt 1: SleepNight-Entität erstellen
In dieser Aufgabe definieren Sie eine Nacht Schlaf als annotierte Datenklasse.
Für eine Nacht Schlaf müssen Sie die Start- und Endzeit sowie eine Qualitätsbewertung aufzeichnen.
Außerdem benötigen Sie eine ID, um die Nacht eindeutig zu identifizieren.
- Suchen Sie im Paket
databasenach der DateiSleepNight.ktund öffnen Sie sie. - Erstelle die Datenklasse
SleepNightmit Parametern für eine ID, eine Startzeit (in Millisekunden), eine Endzeit (in Millisekunden) und eine numerische Bewertung der Schlafqualität.
- Sie müssen
sleepQualityinitialisieren und auf-1setzen, um anzugeben, dass keine Qualitätsdaten erhoben wurden. - Sie müssen auch die Endzeit initialisieren. Legen Sie sie auf die Startzeit fest, um anzugeben, dass noch keine Endzeit aufgezeichnet wurde.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)- Annotieren Sie die Datenklasse vor der Klassendeklaration mit
@Entity. Geben Sie der Tabelle den Namendaily_sleep_quality_table. Das Argument fürtableNameist optional, wird aber empfohlen. Weitere Argumente finden Sie in der Dokumentation.
Importieren Sie bei AufforderungEntityund alle anderen Anmerkungen aus derandroidx-Bibliothek.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)- Wenn Sie
nightIdals Primärschlüssel festlegen möchten, kommentieren Sie die PropertynightIdmit@PrimaryKey. Legen Sie den ParameterautoGenerateauftruefest, damitRoomdie ID für jede Einheit generiert. So wird sichergestellt, dass die ID für jede Nacht eindeutig ist.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...- Kommentieren Sie die verbleibenden Properties mit
@ColumnInfo. Passen Sie die Attributnamen mit Parametern an, wie unten dargestellt.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)- Erstellen und führen Sie Ihren Code aus, um sicherzustellen, dass er keine Fehler enthält.
In dieser Aufgabe definieren Sie ein Data Access Object (DAO). Unter Android bietet das DAO praktische Methoden zum Einfügen, Löschen und Aktualisieren der Datenbank.
Wenn Sie eine Room-Datenbank verwenden, fragen Sie die Datenbank ab, indem Sie Kotlin-Funktionen in Ihrem Code definieren und aufrufen. Diese Kotlin-Funktionen werden SQL-Abfragen zugeordnet. Sie definieren diese Zuordnungen in einem DAO mithilfe von Annotationen und Room generiert den erforderlichen Code.
Ein DAO definiert eine benutzerdefinierte Schnittstelle für den Zugriff auf Ihre Datenbank.
Für gängige Datenbankvorgänge bietet die Room-Bibliothek praktische Anmerkungen wie @Insert, @Delete und @Update. Für alles andere gibt es die Annotation @Query. Sie können jede Abfrage schreiben, die von SQLite unterstützt wird.
Wenn Sie Ihre Abfragen in Android Studio erstellen, prüft der Compiler Ihre SQL-Abfragen auf Syntaxfehler.
Für die Schlaftracker-Datenbank mit Schlafnächten müssen Sie Folgendes tun können:
- Fügen Sie neue Nächte ein.
- Aktualisieren Sie eine bestehende Nacht, um eine Endzeit und eine Qualitätsbewertung zu aktualisieren.
- Get (Abrufen) einer bestimmten Nacht anhand ihres Schlüssels.
- Alle Nächte abrufen, damit sie angezeigt werden können.
- Die letzte Nacht ansehen
- Löschen Sie alle Einträge in der Datenbank.
Schritt 1: SleepDatabase-DAO erstellen
- Öffnen Sie im Paket
databasedie DateiSleepDatabaseDao.kt. - Beachten Sie, dass
interfaceSleepDatabaseDaomit@Daoannotiert ist. Alle DAOs müssen mit dem Schlüsselwort@Daoannotiert werden.
@Dao
interface SleepDatabaseDao {}- Fügen Sie im Body der Schnittstelle eine
@Insert-Annotation hinzu. Fügen Sie unter@Inserteineinsert()-Funktion hinzu, die eine Instanz derEntity-KlasseSleepNightals Argument verwendet.
Das war's auch schon.Roomgeneriert den gesamten erforderlichen Code, umSleepNightin die Datenbank einzufügen. Wenn Sieinsert()in Ihrem Kotlin-Code aufrufen, führtRoomeine SQL-Abfrage aus, um die Entität in die Datenbank einzufügen. Hinweis: Sie können die Funktion beliebig benennen.
@Insert
fun insert(night: SleepNight)- Fügen Sie für ein
SleepNightdie Annotation@Updatemit einerupdate()-Funktion hinzu. Die aktualisierte Entität ist die Entität mit demselben Schlüssel wie der übergebene Schlüssel. Sie können einige oder alle anderen Attribute der Entität aktualisieren.
@Update
fun update(night: SleepNight)Für die verbleibende Funktionalität gibt es keine Convenience-Annotation. Sie müssen also die Annotation @Query verwenden und SQLite-Abfragen angeben.
- Fügen Sie eine
@Query-Annotation mit einerget()-Funktion hinzu, die einLong-key-Argument akzeptiert und einen nullableSleepNight-Wert zurückgibt. Es wird ein Fehler für einen fehlenden Parameter angezeigt.
@Query
fun get(key: Long): SleepNight?- Die Abfrage wird als Stringparameter an die Anmerkung übergeben. Fügen Sie
@Queryeinen Parameter hinzu. Erstelle eineString, die eine SQLite-Abfrage ist.
- Alle Spalten aus der
daily_sleep_quality_table-Tabelle auswählen WHERE–nightIdstimmt mit dem Argument :keyüberein.
Beachten Sie die:key. Sie verwenden die Doppelpunktnotation in der Abfrage, um auf Argumente in der Funktion zu verweisen.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")- Fügen Sie ein weiteres
@Querymit einerclear()-Funktion und einer SQLite-Abfrage hinzu, um alles aus demdaily_sleep_quality_tablezuDELETE. Mit dieser Abfrage wird die Tabelle selbst nicht gelöscht.
Mit der Annotation@Deletewird ein Element gelöscht. Sie können@Deleteverwenden und eine Liste der zu löschenden Nächte angeben. Der Nachteil ist, dass Sie abrufen müssen, was in der Tabelle enthalten ist, oder es wissen müssen. Die Annotation@Deleteeignet sich gut zum Löschen bestimmter Einträge, ist aber nicht effizient, um alle Einträge aus einer Tabelle zu entfernen.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()- Fügen Sie ein
@Querymit einergetTonight()-Funktion hinzu. Machen Sie den vongetTonight()zurückgegebenenSleepNightnullable, damit die Funktion den Fall verarbeiten kann, in dem die Tabelle leer ist. Die Tabelle ist am Anfang und nach dem Löschen der Daten leer.
Schreibe eine SQLite-Abfrage, die das erste Element einer Liste von Ergebnissen zurückgibt, die nachnightIdin absteigender Reihenfolge sortiert sind, um „heute Abend“ aus der Datenbank abzurufen. Verwenden SieLIMIT 1, um nur ein Element zurückzugeben.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?- Fügen Sie ein
@Querymit einergetAllNights()-Funktion hinzu:
- Lassen Sie von der SQLite-Abfrage alle Spalten aus
daily_sleep_quality_tablein absteigender Reihenfolge zurückgeben. - Lass
getAllNights()eine Liste vonSleepNight-Entitäten alsLiveDatazurückgeben.RoomhältLiveDatafür Sie auf dem neuesten Stand. Sie müssen die Daten also nur einmal explizit abrufen. - Möglicherweise müssen Sie
LiveDataausandroidx.lifecycle.LiveDataimportieren.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>- Obwohl keine sichtbaren Änderungen vorgenommen werden, sollten Sie Ihre App ausführen, um sicherzugehen, dass sie keine Fehler enthält.
In dieser Aufgabe erstellen Sie eine Room-Datenbank, die die Entity und das DAO verwendet, die Sie in der vorherigen Aufgabe erstellt haben.
Sie müssen eine abstrakte Datenbank-Holder-Klasse erstellen, die mit @Database annotiert ist. Diese Klasse hat eine Methode, die entweder eine Instanz der Datenbank erstellt, wenn die Datenbank nicht vorhanden ist, oder einen Verweis auf eine vorhandene Datenbank zurückgibt.
Das Abrufen einer Room-Datenbank ist etwas aufwendig. Hier ist der allgemeine Ablauf, bevor Sie mit dem Code beginnen:
- Erstelle eine
public abstract-Klasse, dieextends RoomDatabase. Diese Klasse dient als Datenbankhalter. Die Klasse ist abstrakt, daRoomdie Implementierung für Sie erstellt. - Kommentieren Sie die Klasse mit
@Database. Deklarieren Sie in den Argumenten die Entitäten für die Datenbank und legen Sie die Versionsnummer fest. - Definieren Sie in einem
companion-Objekt eine abstrakte Methode oder Property, die einenSleepDatabaseDaozurückgibt.Roomgeneriert den Text für Sie. - Sie benötigen nur eine Instanz der
Room-Datenbank für die gesamte App. Machen SieRoomDatabasedaher zu einem Singleton. - Verwenden Sie den Datenbank-Builder von
Room, um die Datenbank nur zu erstellen, wenn sie nicht vorhanden ist. Andernfalls wird die vorhandene Datenbank zurückgegeben.
Schritt 1: Datenbank erstellen
- Öffnen Sie im Paket
databasedie DateiSleepDatabase.kt. - Erstellen Sie in der Datei eine
abstract-Klasse mit dem NamenSleepDatabase, dieRoomDatabase.
erweitert. Annotieren Sie die Klasse mit@Database.
@Database()
abstract class SleepDatabase : RoomDatabase() {}- Es wird ein Fehler für fehlende Entitäten und Versionsparameter angezeigt. Für die Annotation
@Databasesind mehrere Argumente erforderlich, damitRoomdie Datenbank erstellen kann.
- Geben Sie
SleepNightals einziges Element in der Liste vonentitiesan. - Legen Sie
versionals1fest. Wenn Sie das Schema ändern, müssen Sie die Versionsnummer erhöhen. - Legen Sie
exportSchemaauffalsefest, damit keine Sicherungen des Schemaversionsverlaufs erstellt werden.
entities = [SleepNight::class], version = 1, exportSchema = false- Die Datenbank muss das DAO kennen. Deklarieren Sie im Hauptteil der Klasse einen abstrakten Wert, der den
SleepDatabaseDaozurückgibt. Sie können mehrere DAOs haben.
abstract val sleepDatabaseDao: SleepDatabaseDao- Definieren Sie darunter ein
companion-Objekt. Über das Companion-Objekt können Clients auf die Methoden zum Erstellen oder Abrufen der Datenbank zugreifen, ohne die Klasse instanziieren zu müssen. Da diese Klasse nur dazu dient, eine Datenbank bereitzustellen, gibt es keinen Grund, sie zu instanziieren.
companion object {}- Deklarieren Sie im
companion-Objekt eine private, nullable VariableINSTANCEfür die Datenbank und initialisieren Sie sie mitnull. Die VariableINSTANCEenthält eine Referenz zur Datenbank, sobald eine erstellt wurde. So müssen Sie nicht immer wieder Verbindungen zur Datenbank öffnen, was ressourcenintensiv ist.
Kommentieren Sie INSTANCE mit @Volatile. Der Wert einer flüchtigen Variablen wird nie im Cache gespeichert und alle Schreib- und Lesevorgänge erfolgen im Hauptspeicher. So wird sichergestellt, dass der Wert von INSTANCE immer aktuell und für alle Ausführungs-Threads gleich ist. Das bedeutet, dass Änderungen, die von einem Thread an INSTANCE vorgenommen werden, sofort für alle anderen Threads sichtbar sind. So wird verhindert, dass beispielsweise zwei Threads dasselbe Element in einem Cache aktualisieren, was zu Problemen führen würde.
@Volatile
private var INSTANCE: SleepDatabase? = null- Definieren Sie unter
INSTANCE, aber noch innerhalb descompanion-Objekts, einegetInstance()-Methode mit einemContext-Parameter, den der Datenbank-Builder benötigt. Gibt den TypSleepDatabasezurück. Es wird ein Fehler angezeigt, dagetInstance()noch nichts zurückgibt.
fun getInstance(context: Context): SleepDatabase {}- Fügen Sie in
getInstance()einensynchronized{}-Block ein. Übergeben Siethis, damit Sie auf den Kontext zugreifen können.
Mehrere Threads können gleichzeitig eine Datenbankinstanz anfordern, was zu zwei Datenbanken anstelle von einer führt. Dieses Problem tritt in dieser Beispiel-App wahrscheinlich nicht auf, ist aber bei komplexeren Apps möglich. Wenn Sie den Code zum Abrufen der Datenbank insynchronizedeinschließen, kann jeweils nur ein Ausführungsthread in diesen Codeblock eintreten. So wird sichergestellt, dass die Datenbank nur einmal initialisiert wird.
synchronized(this) {}- Kopieren Sie im synchronisierten Block den aktuellen Wert von
INSTANCEin eine lokale Variableinstance. So können Sie Smart Cast nutzen, das nur für lokale Variablen verfügbar ist.
var instance = INSTANCE- Im
synchronized-Block:return instanceam Ende dessynchronized-Blocks. Ignorieren Sie den Fehler wegen des nicht übereinstimmenden Rückgabetyps. Sie werden nach Abschluss der Aufgabe niemals „null“ zurückgeben.
return instance- Fügen Sie über der
return-Anweisung eineif-Anweisung hinzu, um zu prüfen, obinstancenull ist, d. h. ob noch keine Datenbank vorhanden ist.
if (instance == null) {}- Wenn
instancegleichnullist, verwenden Sie den Datenbank-Builder, um eine Datenbank zu erhalten. Rufen Sie im Hauptteil derif-AnweisungRoom.databaseBuilderauf und geben Sie den übergebenen Kontext, die Datenbankklasse und einen Namen für die Datenbank an,sleep_history_database. Um den Fehler zu beheben, müssen Sie in den folgenden Schritten eine Migrationsstrategie undbuild()hinzufügen.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")- Fügen Sie dem Builder die erforderliche Migrationsstrategie hinzu. Verwenden Sie
.fallbackToDestructiveMigration().
Normalerweise müssten Sie ein Migrationsobjekt mit einer Migrationsstrategie für den Fall bereitstellen, dass sich das Schema ändert. Ein Migrationsobjekt ist ein Objekt, das definiert, wie alle Zeilen mit dem alten Schema in Zeilen mit dem neuen Schema konvertiert werden, damit keine Daten verloren gehen. Die Migration wird in diesem Codelab nicht behandelt. Eine einfache Lösung besteht darin, die Datenbank zu zerstören und neu zu erstellen. Dabei gehen die Daten jedoch verloren.
.fallbackToDestructiveMigration()- Rufen Sie abschließend
.build()auf.
.build()- Weisen Sie
INSTANCE = instanceals letzten Schritt in derif-Anweisung zu.
INSTANCE = instance- Ihr endgültiger Code sollte so aussehen:
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}- Code erstellen und ausführen
Sie haben jetzt alle Bausteine, um mit Ihrer Room-Datenbank zu arbeiten. Dieser Code wird kompiliert und ausgeführt, aber Sie können nicht feststellen, ob er tatsächlich funktioniert. Jetzt ist also ein guter Zeitpunkt, einige grundlegende Tests hinzuzufügen.
Schritt 2: SleepDatabase testen
In diesem Schritt führen Sie die bereitgestellten Tests aus, um zu prüfen, ob Ihre Datenbank funktioniert. So können Sie sicher sein, dass die Datenbank funktioniert, bevor Sie sie weiter ausbauen. Die bereitgestellten Tests sind einfach. Bei einer Produktions-App würden Sie alle Funktionen und Abfragen in allen DAOs ausführen.
Die Starter-App enthält den Ordner androidTest. Dieser androidTest-Ordner enthält Unittests, die Android-Instrumentierung umfassen. Das bedeutet, dass für die Tests das Android-Framework erforderlich ist. Sie müssen die Tests also auf einem physischen oder virtuellen Gerät ausführen. Natürlich können Sie auch reine Unit-Tests erstellen und ausführen, die das Android-Framework nicht einbeziehen.
- Öffnen Sie in Android Studio im Ordner androidTest die Datei SleepDatabaseTest.
- Wenn Sie den Kommentar aus dem Code entfernen möchten, wählen Sie den gesamten kommentierten Code aus und drücken Sie die Tastenkombination
Cmd+/oderControl+/. - Sehen Sie sich die Datei an.
Hier ist ein kurzer Überblick über den Testcode, da es sich um einen weiteren Codeabschnitt handelt, den Sie wiederverwenden können:
SleepDabaseTestist eine Testklasse.- Mit der Annotation
@RunWithwird der Test-Runner identifiziert. Das ist das Programm, das die Tests einrichtet und ausführt. - Während der Einrichtung wird die mit
@Beforeannotierte Funktion ausgeführt und es wird eine speicherinterneSleepDatabasemit derSleepDatabaseDaoerstellt. „Im Arbeitsspeicher“ bedeutet, dass diese Datenbank nicht im Dateisystem gespeichert wird und nach dem Ausführen der Tests gelöscht wird. - Beim Erstellen der In-Memory-Datenbank wird im Code auch eine weitere testspezifische Methode aufgerufen:
allowMainThreadQueries. Standardmäßig wird ein Fehler ausgegeben, wenn Sie versuchen, Abfragen im Hauptthread auszuführen. Mit dieser Methode können Sie Tests im Hauptthread ausführen. Das sollten Sie jedoch nur während des Testens tun. - In einer Testmethode, die mit
@Testannotiert ist, erstellen, fügen Sie einSleepNightein und rufen es ab. Anschließend prüfen Sie, ob die beiden Objekte identisch sind. Wenn etwas schiefgeht, lösen Sie eine Ausnahme aus. In einem echten Test hätten Sie mehrere@Test-Methoden. - Nach Abschluss der Tests wird die mit
@Afterannotierte Funktion ausgeführt, um die Datenbank zu schließen.
- Klicken Sie im Bereich Project (Projekt) mit der rechten Maustaste auf die Testdatei und wählen Sie Run 'SleepDatabaseTest' (SleepDatabaseTest ausführen) aus.
- Prüfe nach dem Ausführen der Tests im Bereich SleepDatabaseTest, ob alle Tests bestanden wurden.

Da alle Tests bestanden wurden, wissen Sie jetzt Folgendes:
- Die Datenbank wird korrekt erstellt.
- Sie können einen
SleepNightin die Datenbank einfügen. - Sie können die
SleepNightzurückerhalten. SleepNighthat den richtigen Wert für die Qualität.
Android Studio-Projekt: TrackMySleepQualityRoomAndTesting
Beim Testen einer Datenbank müssen Sie alle im DAO definierten Methoden ausführen. Um die Tests abzuschließen , fügen Sie Tests hinzu und führen Sie sie aus, um die anderen DAO-Methoden zu testen.
- Definieren Sie Ihre Tabellen als Datenklassen, die mit
@Entityannotiert sind. Definieren Sie Attribute, die mit@ColumnInfogekennzeichnet sind, als Spalten in den Tabellen. - Definieren Sie ein Data Access Object (DAO) als Schnittstelle mit der Annotation
@Dao. Das DAO bildet Kotlin-Funktionen auf Datenbankabfragen ab. - Verwenden Sie Annotationen, um die Funktionen
@Insert,@Deleteund@Updatezu definieren. - Verwenden Sie die Annotation
@Querymit einem SQLite-Abfragestring als Parameter für alle anderen Abfragen. - Erstellen Sie eine abstrakte Klasse mit einer
getInstance()-Funktion, die eine Datenbank zurückgibt. - Verwenden Sie instrumentierte Tests, um zu prüfen, ob Ihre Datenbank und Ihr DAO wie erwartet funktionieren. Sie können die bereitgestellten Tests als Vorlage verwenden.
Udacity-Kurs:
Android-Entwicklerdokumentation:
RoomDatabaseDatabase(Anmerkungen)- Rohabfragen mit
Roomverwenden Roomdatabase.Builder- Schulung zum Testen
SQLiteDatabase-KlasseDaoRoom-Persistenzbibliothek
Weitere Dokumentation und Artikel:
In diesem Abschnitt werden mögliche Hausaufgaben für Schüler und Studenten aufgeführt, die dieses Codelab im Rahmen eines von einem Kursleiter geleiteten Kurses durcharbeiten. Es liegt in der Verantwortung des Kursleiters, Folgendes zu tun:
- Weisen Sie bei Bedarf Aufgaben zu.
- Teilen Sie den Schülern/Studenten mit, wie sie Hausaufgaben abgeben können.
- Benoten Sie die Hausaufgaben.
Lehrkräfte können diese Vorschläge nach Belieben nutzen und auch andere Hausaufgaben zuweisen, die sie für angemessen halten.
Wenn Sie dieses Codelab selbst durcharbeiten, können Sie mit diesen Hausaufgaben Ihr Wissen testen.
Beantworten Sie diese Fragen
Frage 1
Wie geben Sie an, dass eine Klasse eine Entität darstellt, die in einer Room-Datenbank gespeichert werden soll?
- Lassen Sie die Klasse
DatabaseEntityerweitern. - Kommentieren Sie die Klasse mit
@Entity. - Kommentieren Sie die Klasse mit
@Database. - Lassen Sie die Klasse
RoomEntityerweitern und annotieren Sie die Klasse auch mit@Room.
Frage 2
Das DAO (Data Access Object) ist eine Schnittstelle, die von Room verwendet wird, um Kotlin-Funktionen Datenbankabfragen zuzuordnen.
Wie geben Sie an, dass eine Schnittstelle ein DAO für eine Room-Datenbank darstellt?
- Lassen Sie die Schnittstelle
RoomDAOerweitern. - Lassen Sie die Schnittstelle
EntityDaoerweitern und implementieren Sie dann die MethodeDaoConnection(). - Kommentieren Sie die Schnittstelle mit
@Dao. - Kommentieren Sie die Schnittstelle mit
@RoomConnection.
Frage 3
Welche der folgenden Aussagen zur Room-Datenbank sind richtig? Wählen Sie alle zutreffenden Antworten aus.
- Sie können Tabellen für eine
Room-Datenbank als annotierte Datenklassen definieren. - Wenn Sie
LiveDataaus einer Abfrage zurückgeben, wirdRoomfür Sie aktualisiert, wenn sichLiveDataändert.LiveData - Jede
Room-Datenbank muss genau ein DAO haben. - Wenn Sie eine Klasse als
Room-Datenbank kennzeichnen möchten, machen Sie sie zu einer abgeleiteten Klasse vonRoomDatabaseund versehen Sie sie mit der Annotation@Database.
Frage 4
Welche der folgenden Anmerkungen können Sie in Ihrer @Dao-Benutzeroberfläche verwenden? Wählen Sie alle zutreffenden Antworten aus.
@Get@Update@Insert@Query
Frage 5
Wie können Sie prüfen, ob Ihre Datenbank funktioniert? Wähle alle zutreffenden Antworten aus.
- Instrumentierte Tests schreiben
- Schreiben Sie die App weiter und führen Sie sie aus, bis die Daten angezeigt werden.
- Ersetzen Sie die Aufrufe der Methoden in der DAO-Schnittstelle durch Aufrufe der entsprechenden Methoden in der Klasse
Entity. - Führen Sie die Funktion
verifyDatabase()aus, die von der BibliothekRoombereitgestellt wird.
Nächste Lektion:
Links zu anderen Codelabs in diesem Kurs finden Sie auf der Landingpage für Android Kotlin Fundamentals-Codelabs.