Die Room Persistence Library bietet eine Abstraktionsebene über SQLite, um einen robusteren Datenbankzugriff zu ermöglichen und gleichzeitig die volle Leistung von SQLite zu nutzen. Auf dieser Seite geht es vorrangig um die Verwendung von Room in Kotlin Multiplatform-Projekten (KMP). Weitere Informationen zur Verwendung von Room finden Sie unter Daten mit Room in einer lokalen Datenbank speichern oder in unseren offiziellen Beispielen.
Abhängigkeiten einrichten
Die aktuelle Version von Room, die KMP unterstützt, ist 2.7.0-alpha01 oder höher.
Fügen Sie die Abhängigkeiten für die Artefakte in der Datei build.gradle.kts
für Ihr Modul hinzu, um Room in Ihrem KMP-Projekt einzurichten:
androidx.room:room-gradle-plugin
– Das Gradle-Plug-in zum Konfigurieren von Raumschemasandroidx.room:room-compiler
– der KSP-Prozessor, der den Code generiertandroidx.room:room-runtime
– Laufzeitteil der Bibliothekandroidx.sqlite:sqlite-bundled
(optional): Die gebündelte SQLite-Bibliothek.
Außerdem müssen Sie den SQLite-Treiber für Room konfigurieren. Diese Treiber unterscheiden sich je nach Zielplattform. Unter Treiberimplementierungen finden Sie Beschreibungen der verfügbaren Treiberimplementierungen.
Hier finden Sie weitere Informationen zur Einrichtung:
- Schemaspeicherort mit dem Room Gradle-Plug-in festlegen
- KSP mit Kotlin Multiplatform.
- Laufzeitabhängigkeiten hinzufügen
Datenbankklassen definieren
Sie müssen eine Datenbankklasse erstellen, die mit @Database
zusammen mit DAOs und Entitäten im gemeinsamen Quellsatz des freigegebenen KMP-Moduls annotiert ist. Wenn Sie diese Klassen in gemeinsamen Quellen platzieren, können sie auf allen Zielplattformen gemeinsam genutzt werden.
// shared/src/commonMain/kotlin/Database.kt
@Database(entities = [TodoEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun getDao(): TodoDao
}
@Dao
interface TodoDao {
@Insert
suspend fun insert(item: TodoEntity)
@Query("SELECT count(*) FROM TodoEntity")
suspend fun count(): Int
@Query("SELECT * FROM TodoEntity")
fun getAllAsFlow(): Flow<List<TodoEntity>>
}
@Entity
data class TodoEntity(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val title: String,
val content: String
)
Sie können tatsächliche / erwartete Deklarationen verwenden, um plattformspezifische Raumimplementierungen zu erstellen. Sie haben beispielsweise die Möglichkeit, mit expect
einen plattformspezifischen DAO hinzuzufügen, der im gemeinsamen Code definiert ist, und dann die actual
-Definitionen mit zusätzlichen Abfragen in plattformspezifischen Quellsätzen angeben.
Datenbank-Builder erstellen
Sie müssen einen Datenbank-Builder definieren, um Room auf jeder Plattform zu instanziieren. Dies ist der einzige Teil der API, der aufgrund der Unterschiede bei den Dateisystem-APIs in plattformspezifischen Quellsätzen enthalten sein muss. Bei Android wird der Speicherort der Datenbank normalerweise über die Context.getDatabasePath()
API abgerufen. Bei iOS hingegen wird der Speicherort der Datenbank mit NSHomeDirectory
abgerufen.
Android
Geben Sie zum Erstellen der Datenbankinstanz einen Kontext zusammen mit dem Datenbankpfad an. Sie müssen keine Datenbank-Factory angeben.
// shared/src/androidMain/kotlin/Database.kt
fun getDatabaseBuilder(ctx: Context): RoomDatabase.Builder<AppDatabase> {
val appContext = ctx.applicationContext
val dbFile = appContext.getDatabasePath("my_room.db")
return Room.databaseBuilder<AppDatabase>(
context = appContext,
name = dbFile.absolutePath
)
}
iOS
Geben Sie zum Erstellen der Datenbankinstanz eine Datenbank-Factory zusammen mit dem Datenbankpfad an. Die Datenbank-Factory ist eine Lambda-Funktion, die eine generierte Erweiterungsfunktion mit dem Namen instantiateImpl
und einem Empfänger vom Typ KClass<T>
aufruft, wobei T
der Typ der annotierten Klasse @Database
ist.
// shared/src/iosMain/kotlin/Database.kt
fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFilePath = NSHomeDirectory() + "/my_room.db"
return Room.databaseBuilder<AppDatabase>(
name = dbFilePath,
factory = { AppDatabase::class.instantiateImpl() }
)
}
JVM (Desktop)
Geben Sie zum Erstellen der Datenbankinstanz nur den Datenbankpfad an. Sie müssen keine Datenbank-Factory angeben.
// shared/src/commonMain/kotlin/Database.kt
fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFile = File(System.getProperty("java.io.tmpdir"), "my_room.db")
return Room.databaseBuilder<AppDatabase>(
name = dbFile.absolutePath,
)
}
Datenbankinstanziierung
Nachdem Sie die RoomDatabase.Builder
von einem der plattformspezifischen Konstruktoren abgerufen haben, können Sie den Rest der Room-Datenbank mit dem gemeinsamen Code zusammen mit der tatsächlichen Datenbankinstanziierung konfigurieren.
// shared/src/commonMain/kotlin/Database.kt
fun getRoomDatabase(
builder: RoomDatabase.Builder<AppDatabase>
): AppDatabase {
return builder
.addMigrations(MIGRATIONS)
.fallbackToDestructiveMigrationOnDowngrade()
.setDriver(BundledSQLiteDriver())
.setQueryCoroutineContext(Dispatchers.IO)
.build()
}
SQLiteDriver auswählen
In den vorherigen Code-Snippets wird BundledSQLiteDriver
verwendet. Dies ist der empfohlene Treiber, der aus der Quelle kompiliert SQLite enthält. Damit erhalten Sie auf allen Plattformen die konsistentste und aktuellste Version von SQLite. Wenn Sie das vom Betriebssystem bereitgestellte SQLite verwenden möchten, nutzen Sie die setDriver
API in plattformspezifischen Quellsätzen, die einen plattformspezifischen Treiber angeben. Für Android können Sie AndroidSQLiteDriver
und für iOS NativeSQLiteDriver
verwenden. Wenn Sie NativeSQLiteDriver
verwenden möchten, müssen Sie eine Verknüpfungsoption angeben, damit die iOS-App dynamisch mit dem SQLite-System verknüpft wird.
// shared/build.gradle.kts
kotlin {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "TodoApp"
isStatic = true
// Required when using NativeSQLiteDriver
linkerOpts.add("-lsqlite3")
}
}
}
Unterschiede
Room wurde ursprünglich als Android-Bibliothek entwickelt und später zu KMP migriert, wobei der Schwerpunkt auf der API-Kompatibilität lag. Die KMP-Version von Room unterscheidet sich je nach Plattform und von der Android-spezifischen Version geringfügig. Diese Unterschiede sind wie unten aufgeführt und beschrieben.
DAO-Funktionen blockieren
Wenn Sie Room for KMP verwenden, müssen alle DAO-Funktionen, die für Nicht-Android-Plattformen kompiliert wurden, suspend
-Funktionen sein. Eine Ausnahme bilden reaktive Rückgabetypen wie Flow
.
// shared/src/commonMain/kotlin/MultiplatformDao.kt
@Dao
interface MultiplatformDao {
// ERROR: Blocking function not valid for non-Android targets
@Query("SELECT * FROM Entity")
fun blockingQuery(): List<Entity>
// OK
@Query("SELECT * FROM Entity")
suspend fun query(): List<Entity>
// OK
@Query("SELECT * FROM Entity")
fun queryFlow(): Flow<List<Entity>>
// ERROR: Blocking function not valid for non-Android targets
@Transaction
fun blockingTransaction() { // … }
// OK
@Transaction
suspend fun transaction() { // … }
}
Raum profitiert von der asynchronen kotlinx.coroutines
-Bibliothek mit vielen Funktionen, die Kotlin für mehrere Plattformen bietet. Für eine optimale Funktionalität werden suspend
-Funktionen für DAOs erzwungen, die in einem KMP-Projekt kompiliert wurden. Eine Ausnahme bilden Android-spezifische DAOs, um die Abwärtskompatibilität mit der vorhandenen Codebasis aufrechtzuerhalten.
Funktionsunterschiede zu KMP
In diesem Abschnitt werden die Unterschiede zwischen den KMP- und Android-Plattformversionen von Room beschrieben.
@RawQuery-DAO-Funktionen
Mit @RawQuery
annotierte Funktionen, die für Nicht-Android-Plattformen kompiliert wurden, führen zu einem Fehler. Wir beabsichtigen, die Unterstützung für @RawQuery
in einer zukünftigen Version von Room hinzuzufügen.
Abfragerückruf
Die folgenden APIs zum Konfigurieren von Abfrage-Callbacks sind nicht gemeinsam und daher auf anderen Plattformen als Android nicht verfügbar.
RoomDatabase.Builder.setQueryCallback
RoomDatabase.QueryCallback
Wir planen, die Unterstützung für Rückrufanfragen in einer zukünftigen Version von Room hinzuzufügen.
Die API zum Konfigurieren einer RoomDatabase
mit einem Abfrage-Callback RoomDatabase.Builder.setQueryCallback
und der Callback-Schnittstelle RoomDatabase.QueryCallback
ist nicht gemeinsam und daher auch nicht auf anderen Plattformen als Android verfügbar.
Datenbank automatisch schließen
Die API zum Aktivieren des automatischen Schließens nach einer Zeitüberschreitung,RoomDatabase.Builder.setAutoCloseTimeout
, ist nur unter Android und auf anderen Plattformen nicht verfügbar.
Vorpaketierte Datenbank
Die folgenden APIs zum Erstellen einer RoomDatabase
unter Verwendung einer vorhandenen Datenbank (d.h. einer vorgefertigten Datenbank) sind nicht gemeinsam und daher auch nicht auf anderen Plattformen als Android verfügbar. Diese APIs sind:
RoomDatabase.Builder.createFromAsset
RoomDatabase.Builder.createFromFile
RoomDatabase.Builder.createFromInputStream
RoomDatabase.PrepackagedDatabaseCallback
Wir beabsichtigen, in einer zukünftigen Version von Room Support für vorkonfigurierte Datenbanken zu unterstützen.
Entwertung mehrerer Instanzen
Die API zum Aktivieren der Entwertung mehrerer Instanzen (RoomDatabase.Builder.enableMultiInstanceInvalidation
) ist nur unter Android und weder auf gängigen noch auf anderen Plattformen verfügbar.