La libreria di persistenza della stanza fornisce un livello di astrazione rispetto a SQLite per consentire un accesso più solido al database, sfruttando al contempo tutta la potenza di SQLite. Questa pagina è incentrata sull'utilizzo di Room nei progetti Kotlin Multiplatform (KMP). Per scoprire di più sull'utilizzo di Room, consulta Salvare i dati in un database locale utilizzando Room o consultare i nostri campioni ufficiali.
Configurazione delle dipendenze
La versione corrente della stanza che supporta KMP è 2.7.0-alpha01 o versioni successive.
Per configurare la stanza virtuale nel tuo progetto KMP, aggiungi le dipendenze per gli artefatti nel file build.gradle.kts
per il tuo modulo:
androidx.room:room-gradle-plugin
: il plug-in Gradle per configurare gli schemi delle stanzeandroidx.room:room-compiler
: il processore del principale punto di forza che genera il codiceandroidx.room:room-runtime
: la parte runtime della libreriaandroidx.sqlite:sqlite-bundled
: (facoltativo) la libreria SQLite in bundle
Inoltre, devi configurare il driver SQLite della stanza virtuale. Questi fattori variano in base alla piattaforma di destinazione. Consulta Implementazioni dei driver per le descrizioni delle implementazioni disponibili.
Per ulteriori informazioni sulla configurazione, consulta le seguenti risorse:
- Impostare la posizione dello schema usando il plug-in Room Gradle.
- KSP con Kotlin Multiplatform.
- Aggiunta di dipendenze di runtime.
Definizione delle classi di database
Devi creare una classe di database annotata con @Database
insieme a DAO ed entità all'interno del set di origine comune del tuo modulo KMP condiviso. Se posizioni questi corsi in origini comuni, potrai condividerli tra tutte le piattaforme di destinazione.
// 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
)
Tieni presente che puoi utilizzare dichiarazioni effettive / attese per creare implementazioni di stanze specifiche per piattaforma. Ad esempio, puoi aggiungere un DAO specifico per piattaforma definito nel codice comune utilizzando expect
e poi specificare le definizioni di actual
con query aggiuntive in set di origini specifici della piattaforma.
Creazione del generatore di database
Devi definire un generatore di database per creare un'istanza della stanza su ogni piattaforma. Questa è l'unica parte dell'API che deve essere in set di origini specifici della piattaforma a causa delle differenze nelle API del file system. Ad esempio, in Android la posizione del database si ottiene solitamente tramite l'API Context.getDatabasePath()
, mentre per iOS la posizione del database si ottiene utilizzando NSHomeDirectory
.
Android
Per creare l'istanza di database, specifica un Contesto e il percorso del database. Non è necessario specificare una fabbrica di database.
// 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
Per creare l'istanza di database, indica un valore di fabbrica del database insieme al percorso del database. La fabbrica del database è una funzione lambda che richiama una funzione di estensione generata il cui nome è instantiateImpl
con un ricevitore di tipo KClass<T>
, dove T
è il tipo della classe annotata @Database
.
// 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 (computer)
Per creare l'istanza di database, specifica solo il percorso del database. Non è necessario specificare un valore di fabbrica per il database.
// 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,
)
}
Istanza del database
Dopo aver ottenuto il RoomDatabase.Builder
da uno dei costruttori specifici della piattaforma, puoi configurare il resto del database delle stanze nel codice comune insieme all'effettiva istanza del database.
// shared/src/commonMain/kotlin/Database.kt
fun getRoomDatabase(
builder: RoomDatabase.Builder<AppDatabase>
): AppDatabase {
return builder
.addMigrations(MIGRATIONS)
.fallbackToDestructiveMigrationOnDowngrade()
.setDriver(BundledSQLiteDriver())
.setQueryCoroutineContext(Dispatchers.IO)
.build()
}
Selezione di un SQLiteDriver
Gli snippet di codice precedenti utilizzano il parametro BundledSQLiteDriver
. Questo è il driver consigliato che include SQLite compilato dall'origine, che fornisce la versione più coerente e aggiornata di SQLite su tutte le piattaforme. Se
vuoi utilizzare l'API SQLite fornita dal sistema operativo, usa l'API setDriver
in set di origini specifici della piattaforma
che specificano un driver specifico per la piattaforma. Per Android, puoi usare
AndroidSQLiteDriver
, mentre per iOS puoi usare NativeSQLiteDriver
. Per utilizzare NativeSQLiteDriver
, devi fornire un'opzione di linker in modo che l'app per iOS si colleghi in modo dinamico al sistema 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")
}
}
}
Differenze
Room è stato originariamente sviluppato come libreria Android, ma è stata successivamente migrata a KMP con particolare attenzione alla compatibilità delle API. La versione KMP di Room è leggermente diversa a seconda delle piattaforme e della versione specifica per Android. Queste differenze sono elencate e descritte come segue.
Blocco delle funzioni DAO
Quando si utilizza Room for KMP, tutte le funzioni DAO compilate per piattaforme non Android
devono essere funzioni suspend
, ad eccezione dei tipi restituiti reattivi,
come 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() { // … }
}
La camera beneficia della libreria kotlinx.coroutines
asincrona, ricca di funzionalità
offerta da Kotlin per diverse piattaforme. Per una funzionalità ottimale, le funzioni suspend
vengono applicate ai DAO compilati in un progetto KMP, ad eccezione dei DAO specifici di Android per mantenere la compatibilità con le versioni precedenti con il codebase esistente.
Differenze delle funzionalità con KMP
Questa sezione descrive in che modo le funzionalità differiscono tra le versioni della piattaforma KMP e Android di Room.
Funzioni DAO @RawQuery
Le funzioni annotate con @RawQuery
e compilate per piattaforme non Android
generano un errore. Abbiamo intenzione di aggiungere il supporto per @RawQuery
in una versione futura
della stanza virtuale.
Callback della query
Le seguenti API per la configurazione dei callback delle query non sono comuni e non sono quindi disponibili su piattaforme diverse da Android.
RoomDatabase.Builder.setQueryCallback
RoomDatabase.QueryCallback
Intendiamo aggiungere il supporto per il callback delle query in una versione futura della stanza virtuale.
L'API per configurare un RoomDatabase
con un callback di query
RoomDatabase.Builder.setQueryCallback
e l'interfaccia di callback
RoomDatabase.QueryCallback
non sono comuni e pertanto non sono disponibili
in altre piattaforme diverse da Android.
Chiusura automatica del database
L'API per abilitare la chiusura automatica dopo un timeout, RoomDatabase.Builder.setAutoCloseTimeout
, è disponibile solo su Android e non è disponibile in altre piattaforme.
Database predefinito
Le seguenti API per creare un RoomDatabase
utilizzando un database esistente (ad esempio un database predefinito) non sono disponibili comuni e, pertanto, non lo sono in altre piattaforme diverse da Android. Queste API sono:
RoomDatabase.Builder.createFromAsset
RoomDatabase.Builder.createFromFile
RoomDatabase.Builder.createFromInputStream
RoomDatabase.PrepackagedDatabaseCallback
Abbiamo intenzione di aggiungere il supporto per i database predefiniti in una versione futura della stanza.
Annullamento convalida di più istanze
L'API per abilitare l'annullamento della convalida di più istanze RoomDatabase.Builder.enableMultiInstanceInvalidation
è disponibile solo su Android e non è disponibile tra le piattaforme comuni né in altre piattaforme.