La bibliothèque de persistance Room fournit une couche d'abstraction sur SQLite pour permettre pour un accès plus robuste aux bases de données tout en exploitant toute la puissance de SQLite. Ce se concentre sur l'utilisation de Room dans les projets KMP (Kotlin Multiplatform). Pour plus des informations sur l'utilisation de Room, consultez la section Enregistrer des données dans une base de données locale à l'aide de Room. ou nos exemples officiels.
Configurer des dépendances
La version actuelle de Room compatible avec KMP est 2.7.0-alpha01 ou version ultérieure.
Pour configurer Room dans votre projet KMP, ajoutez les dépendances des artefacts dans le
build.gradle.kts
pour votre module:
androidx.room:room-gradle-plugin
: plug-in Gradle pour configurer les schémas Roomandroidx.room:room-compiler
: processeur KSP qui génère le codeandroidx.room:room-runtime
: partie "environnement d'exécution" de la bibliothèqueandroidx.sqlite:sqlite-bundled
(facultatif) : bibliothèque SQLite intégrée
Vous devez également configurer le pilote SQLite de Room. Ces pilotes sont différents en fonction de la plate-forme cible. Voir Implémentations de pilotes pour obtenir une description des implémentations de pilotes disponibles.
Pour en savoir plus sur la configuration, consultez les pages suivantes:
- Définir l'emplacement du schéma à l'aide du plug-in Room Gradle
- KSP avec la multiplateforme Kotlin.
- Ajouter des dépendances d'exécution
Définir les classes de base de données
Vous devez créer une classe de base de données annotée avec @Database
avec les DAO.
et les entités de l'ensemble de sources commun
de votre module KMP partagé. Positionnement
ces classes dans des sources communes
permettront de les partager entre toutes
plates-formes.
Lorsque vous déclarez un objet expect
avec l'interface
RoomDatabaseConstructor
, le compilateur Room génère le actual
mises en œuvre. Android Studio peut afficher un avertissement
"Expected object 'AppDatabaseConstructor' has no actual declaration in
module"
; vous pouvez supprimer l'avertissement avec @Suppress("NO_ACTUAL_FOR_EXPECT")
.
// shared/src/commonMain/kotlin/Database.kt
@Database(entities = [TodoEntity::class], version = 1)
@ConstructedBy(AppDatabaseConstructor::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun getDao(): TodoDao
}
// The Room compiler generates the `actual` implementations.
@Suppress("NO_ACTUAL_FOR_EXPECT")
expect object AppDatabaseConstructor : RoomDatabaseConstructor<AppDatabase>
@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
)
Notez que vous pouvez éventuellement utiliser des déclarations réelles / attendues.
pour créer des implémentations Room spécifiques à la plate-forme. Par exemple, vous pouvez ajouter
DAO spécifique à la plate-forme défini dans du code commun à l'aide de expect
, puis
spécifier les définitions actual
avec des requêtes supplémentaires dans les paramètres spécifiques à la plate-forme ;
d'ensembles de sources.
Créer le compilateur de base de données
Vous devez définir un générateur de base de données pour instancier Room sur chaque plate-forme. Ce
est la seule partie de l'API qui doit se trouver dans une source spécifique à la plate-forme
en raison des différences
dans les API de système de fichiers. Par exemple, sur Android,
l'emplacement de la base de données est généralement obtenue via
Context.getDatabasePath()
, tandis que pour iOS, l'emplacement de la base de données est
être obtenu à l'aide de NSFileManager
.
Android
Pour créer l'instance de base de données, spécifiez un Context (Contexte) ainsi que la base de données. chemin d'accès.
// 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
Pour créer l'instance de base de données, indiquez un chemin d'accès à la base de données à l'aide de la méthode
NSFileManager
, généralement située dans le NSDocumentDirectory
.
// shared/src/iosMain/kotlin/Database.kt
fun getDatabaseBuilder(): RoomDatabase.Builder<AppDatabase> {
val dbFilePath = documentDirectory() + "/my_room.db"
return Room.databaseBuilder<AppDatabase>(
name = dbFilePath,
)
}
private fun documentDirectory(): String {
val documentDirectory = NSFileManager.defaultManager.URLForDirectory(
directory = NSDocumentDirectory,
inDomain = NSUserDomainMask,
appropriateForURL = null,
create = false,
error = null,
)
return requireNotNull(documentDirectory?.path)
}
JVM (ordinateur de bureau)
Pour créer l'instance de base de données, indiquez un chemin d'accès à la base de données en Java ou Kotlin API.
// shared/src/jvmMain/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,
)
}
Instanciation de base de données
Une fois que vous avez obtenu le RoomDatabase.Builder
auprès de l'un des services
vous pouvez configurer le reste de la base de données Room en code commun
ainsi que l'instanciation réelle de la base de données.
// shared/src/commonMain/kotlin/Database.kt
fun getRoomDatabase(
builder: RoomDatabase.Builder<AppDatabase>
): AppDatabase {
return builder
.addMigrations(MIGRATIONS)
.fallbackToDestructiveMigrationOnDowngrade()
.setDriver(BundledSQLiteDriver())
.setQueryCoroutineContext(Dispatchers.IO)
.build()
}
Sélectionner un pilote SQLite
Les extraits de code précédents utilisent BundledSQLiteDriver
. Il s'agit de la
le pilote recommandé incluant SQLite compilé à partir de la source, qui fournit
la version la plus cohérente et la plus récente de SQLite sur toutes les plateformes. Si vous
si vous souhaitez utiliser SQLite fournie par l'OS, utilisez l'API setDriver
dans les paramètres spécifiques à la plate-forme.
de sources qui spécifient un pilote spécifique à la plate-forme. Pour Android, vous pouvez utiliser
AndroidSQLiteDriver
, tandis que pour iOS, vous pouvez utiliser NativeSQLiteDriver
. À
utilisez NativeSQLiteDriver
, vous devez fournir une option d'éditeur de liens afin qu'iOS
l'application est associée de manière dynamique au système SQLite.
// 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")
}
}
}
Différences
À l'origine, Room a été développé en tant que bibliothèque Android, puis a été migré vers KMP en mettant l'accent sur la compatibilité des API. La version KMP de Room est légèrement différente entre les plateformes et à partir de la version spécifique à Android. Ces différences sont listées et décrites comme suit.
Bloquer des fonctions DAO
Lorsque vous utilisez Room pour KMP, toutes les fonctions DAO sont compilées pour les plates-formes autres qu'Android.
doivent être des fonctions suspend
, à l'exception des types renvoyés réactifs, tels que
en tant que 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() { // … }
}
Avantages de Room grâce à la bibliothèque kotlinx.coroutines
asynchrone riche en fonctionnalités
que Kotlin propose pour de nombreuses plates-formes. Pour un fonctionnement optimal, suspend
sont appliquées aux DAO compilés dans un projet KMP, à l'exception des
des DAO spécifiques à Android afin de maintenir la rétrocompatibilité avec les
de votre codebase.
Différences de fonctionnalités avec KMP
Cette section décrit les différences de fonctionnalités entre KMP et la plate-forme Android. versions de Room.
Fonctions DAO de @RawQuery
Fonctions annotées avec @RawQuery
compilées pour les plates-formes autres qu'Android
devra déclarer un paramètre de type RoomRawQuery
au lieu de
SupportSQLiteQuery
@Dao
interface TodoDao {
@RawQuery
suspend fun getTodos(query RoomRawQuery): List<TodoEntity>
}
Un RoomRawQuery
peut ensuite être utilisé pour créer une requête au moment de l'exécution:
suspend fun getTodosWithLowercaseTitle(title: String): List<TodoEntity> {
val query = RoomRawQuery(
sql = "SELECT * FROM TodoEntity WHERE title = ?"
onBindStatement = {
it.bindText(1, title.lowercase())
}
)
return todosDao.getTodos(query)
}
Rappel de requête
Les API suivantes, qui permettent de configurer des rappels de requête, ne sont pas disponibles en et ne sont donc pas disponibles sur les plates-formes autres qu'Android.
RoomDatabase.Builder.setQueryCallback
RoomDatabase.QueryCallback
Nous prévoyons d'ajouter la prise en charge du rappel de requête dans une future version de Room.
API permettant de configurer un RoomDatabase
avec un rappel de requête
RoomDatabase.Builder.setQueryCallback
avec l'interface de rappel
RoomDatabase.QueryCallback
ne sont pas disponibles en commun et ne sont donc pas disponibles.
sur d'autres plates-formes qu'Android.
Fermeture automatique de la base de données
L'API permettant d'activer la fermeture automatique après un délai d'inactivité
RoomDatabase.Builder.setAutoCloseTimeout
, n'est disponible que sur Android et est
n'est pas disponible sur d'autres plates-formes.
Base de données prête à l'emploi
Les API suivantes permettent de créer un RoomDatabase
à l'aide d'une base de données existante (par exemple,
pré-empaquetée) ne sont pas disponibles en commun et ne sont donc pas disponibles dans
d'autres plateformes
autres qu'Android. Ces API sont les suivantes:
RoomDatabase.Builder.createFromAsset
RoomDatabase.Builder.createFromFile
RoomDatabase.Builder.createFromInputStream
RoomDatabase.PrepackagedDatabaseCallback
Nous prévoyons d'ajouter la prise en charge des bases de données prêtes à l'emploi dans une future version de Pièce.
Invalidation d'instances multiples
L'API permettant d'activer l'invalidation multi-instance
RoomDatabase.Builder.enableMultiInstanceInvalidation
n'est disponible que sur
Android et n'est pas disponible sur la plate-forme courante ni sur d'autres plates-formes.