Bu dokümanda, mevcut bir Oda uygulamasını (Kotlin Multiplatform (KMP)).
Mevcut bir Android kod tabanındaki oda kullanımlarını ortak bir ortak KMP'ye taşıma modülünün zorluk düzeyi, kullanılan Room API'lere veya kod tabanı zaten eş yordamları kullanıyor. Bu bölümde bazı yol gösterici bilgiler ve ipuçları sunulmaktadır oda kullanımlarını ortak bir modüle taşımaya çalışırken.
Öncelikle aralarındaki farkları ve eksiklikleri
Room'un Android sürümü ve KMP sürümü arasındaki
daha fazla bilgi edindiniz. Başarılı bir taşıma işlemi özünde yeniden düzenleme içerir.
SupportSQLite*
API'lerinin kullanımları ve bunları SQLite Driver API'leriyle değiştirme
oda beyanları (@Database
ek açıklamalı sınıf, DAO'lar,
varlıklar vb.) ortak koda dönüştürür.
Devam etmeden önce aşağıdaki bilgileri tekrar inceleyin:
Sonraki bölümlerde başarılı bir dönüşüm için atmanız gereken taşıma.
Destek SQLite'tan SQLite Sürücüsü'ne taşıma
androidx.sqlite.db
ürünündeki API'ler yalnızca Android'de kullanılabilir ve tüm kullanımların olması gerekir.
ve SQLite Sürücü API'leriyle yeniden düzenlendi. Geriye dönük uyumluluk için ve kullandığınız
RoomDatabase
, bir SupportSQLiteOpenHelper.Factory
(ör.
SQLiteDriver
ayarlanmamışsa) Oda, "uyumluluk modunda" davranır burada:
Destek SQLite ve SQLite Driver API'leri beklendiği gibi çalışır. Bu durumda,
tüm Support SQLite öğelerinizi dönüştürmenize gerek kalmaması için artımlı taşıma işlemleri
kullanımlarını SQLite Sürücüsü'ne iletir.
Aşağıda, Support SQLite ve SQLite desteğinin yaygın kullanım örnekleri verilmiştir Sürücü muadilleri:
SQLite desteği (kaynak)
Sonuç vermeyen bir sorgu yürütme
val database: SupportSQLiteDatabase = ...
database.execSQL("ALTER TABLE ...")
Sonuç içeren ancak bağımsız değişken içermeyen bir sorgu yürütme
val database: SupportSQLiteDatabase = ...
database.query("SELECT * FROM Pet").use { cursor ->
while (cusor.moveToNext()) {
// read columns
cursor.getInt(0)
cursor.getString(1)
}
}
Sonuç ve bağımsız değişkenler içeren bir sorgu yürütme
database.query("SELECT * FROM Pet WHERE id = ?", id).use { cursor ->
if (cursor.moveToNext()) {
// row found, read columns
} else {
// row not found
}
}
SQLite Sürücüsü (hedef)
Sonuç vermeyen bir sorgu yürütme
val connection: SQLiteConnection = ...
connection.execSQL("ALTER TABLE ...")
Sonuç içeren ancak bağımsız değişken içermeyen bir sorgu yürütme
val connection: SQLiteConnection = ...
connection.prepare("SELECT * FROM Pet").use { statement ->
while (statement.step()) {
// read columns
statement.getInt(0)
statement.getText(1)
}
}
Sonuç ve bağımsız değişkenler içeren bir sorgu yürütme
connection.prepare("SELECT * FROM Pet WHERE id = ?").use { statement ->
statement.bindInt(1, id)
if (statement.step()) {
// row found, read columns
} else {
// row not found
}
}
Veritabanı işlemi API'lerini doğrudan SupportSQLiteDatabase
içinde
beginTransaction()
, setTransactionSuccessful()
ve endTransaction()
.
Bunlara, runInTransaction()
kullanılarak Oda üzerinden de erişilebilir. Bunları taşı
kullanımları hakkında daha fazla bilgi edinin.
SQLite desteği (kaynak)
İşlem gerçekleştirme (RoomDatabase
kullanarak)
val database: RoomDatabase = ...
database.runInTransaction {
// perform database operations in transaction
}
İşlem gerçekleştirme (SupportSQLiteDatabase
kullanarak)
val database: SupportSQLiteDatabase = ...
database.beginTransaction()
try {
// perform database operations in transaction
database.setTransactionSuccessful()
} finally {
database.endTransaction()
}
SQLite Sürücüsü (hedef)
İşlem gerçekleştirme (RoomDatabase
kullanarak)
val database: RoomDatabase = ...
database.useWriterConnection { transactor ->
transactor.immediateTransaction {
// perform database operations in transaction
}
}
İşlem gerçekleştirme (SQLiteConnection
kullanarak)
val connection: SQLiteConnection = ...
connection.execSQL("BEGIN IMMEDIATE TRANSACTION")
try {
// perform database operations in transaction
connection.execSQL("END TRANSACTION")
} catch(t: Throwable) {
connection.execSQL("ROLLBACK TRANSACTION")
}
Geri çağırma ile ilgili çeşitli geçersiz kılma işlemlerinin de sürücü muadillerine taşınması gerekir:
SQLite desteği (kaynak)
Taşıma alt sınıfları
object Migration_1_2 : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
// ...
}
}
Otomatik taşıma spesifikasyonu alt sınıfları
class AutoMigrationSpec_1_2 : AutoMigrationSpec {
override fun onPostMigrate(db: SupportSQLiteDatabase) {
// ...
}
}
Veritabanı geri çağırma alt sınıfları
object MyRoomCallback : RoomDatabase.Callback {
override fun onCreate(db: SupportSQLiteDatabase) {
// ...
}
override fun onDestructiveMigration(db: SupportSQLiteDatabase) {
// ...
}
override fun onOpen(db: SupportSQLiteDatabase) {
// ...
}
}
SQLite Sürücüsü (hedef)
Taşıma alt sınıfları
object Migration_1_2 : Migration(1, 2) {
override fun migrate(connection: SQLiteConnection) {
// ...
}
}
Otomatik taşıma spesifikasyonu alt sınıfları
class AutoMigrationSpec_1_2 : AutoMigrationSpec {
override fun onPostMigrate(connection: SQLiteConnection) {
// ...
}
}
Veritabanı geri çağırma alt sınıfları
object MyRoomCallback : RoomDatabase.Callback {
override fun onCreate(connection: SQLiteConnection) {
// ...
}
override fun onDestructiveMigration(connection: SQLiteConnection) {
// ...
}
override fun onOpen(connection: SQLiteConnection) {
// ...
}
}
Özetlemek gerekirse, aşağıdaki durumlarda SQLiteDatabase
kullanımlarını SQLiteConnection
ile değiştirin:
RoomDatabase
, geri çağırma geçersiz kılmalarda olduğu gibi kullanılamaz (onMigrate
,
onCreate
vb.) RoomDatabase
varsa temel hesaba erişin
RoomDatabase.useReaderConnection
ve kullanarak veritabanı bağlantısı
- RoomDatabase.useWriterConnection
RoomDatabase.openHelper.writtableDatabase
.
Engellenen DAO işlevlerini, askıya alma işlevlerine dönüştürün
Room'un KMP sürümü, I/O gerçekleştirmek için eş yordamlardan yararlanır
Yapılandırılmış CoroutineContext
üzerinde işlem. Bu, sizin için
işlevleri askıya almak için engelleyen DAO işlevlerini taşımanız gerekir.
DAO işlevini engelleme (kaynak)
@Query("SELECT * FROM Todo")
fun getAllTodos(): List<Todo>
DAO işlevini askıya alma (hedef)
@Query("SELECT * FROM Todo")
suspend fun getAllTodos(): List<Todo>
Mevcut DAO engelleme işlevlerinin, askıya alma işlevlerine taşınması mevcut kod tabanı halihazırda eş yordamlar içermiyorsa karmaşık hale gelir. Eş yordamları kullanmaya başlamak için Android'de koordinler konusuna bakın inceleyebilirsiniz.
Tepkisel dönüş türlerini Akışa dönüştür
Tüm DAO işlevlerinin askıya alma işlevleri olması gerekmez. Döndürülen DAO işlevleri
LiveData
veya RxJava'nın Flowable
gibi reaktif türleri dönüştürülmemelidir.
askıya alabilirsiniz. Ancak LiveData
gibi bazı türler KMP değildir.
uyumlu olmalıdır. Reaktif döndürme türlerine sahip DAO işlevleri
eş yordamlar, eşzamanlı akışlar.
Uyumsuz KMP türü (kaynak)
@Query("SELECT * FROM Todo")
fun getTodosLiveData(): LiveData<List<Todo>>
Uyumlu KMP türü (hedef)
@Query("SELECT * FROM Todo")
fun getTodosFlow(): Flow<List<Todo>>
Akışları kullanmaya başlamak için Android'de Akışlar kullanabilirsiniz.
Eş yordam bağlamı ayarlayın (İsteğe bağlı)
RoomDatabase
, paylaşılan uygulamayla isteğe bağlı olarak yapılandırılabilir
veritabanı gerçekleştirmek için RoomDatabase.Builder.setQueryExecutor()
kullanan yürütücüler
anlamına gelir. Yürütücüler KMP ile uyumlu olmadığından Odanın setQueryExecutor()
API, yaygın kaynaklar için kullanılamaz. Bunun yerine, RoomDatabase
CoroutineContext
ile yapılandırılacak. Bağlam,
RoomDatabase.Builder.setCoroutineContext()
ayarlanmazsa
RoomDatabase
varsayılan olarak Dispatchers.IO
özelliğini kullanacak.
SQLite Sürücüsü ayarlayın
Support SQLite kullanımları, SQLite Sürücü API'lerine taşındıktan sonra
sürücüsünün RoomDatabase.Builder.setDriver
kullanılarak yapılandırılması gerekir. İlgili içeriği oluşturmak için kullanılan
önerilen sürücü BundledSQLiteDriver
. Aşağıdakiler için Sürücü uygulamaları sayfasını inceleyin
mevcut sürücü uygulamalarının açıklamaları
Özel SupportSQLiteOpenHelper.Factory
, şununla yapılandırıldı:
RoomDatabase.Builder.openHelperFactory()
, KMP'de desteklenmez.
özel açık yardımcı tarafından sağlanan özelliklerin
SQLite Sürücü arayüzleri.
Oda bildirimlerini taşı
Taşıma işlemi adımlarının çoğu tamamlandıktan sonra Oda taşınabilir.
tanımlarını ortak bir kaynak kümesiyle ilişkilendireceğiz. expect
/ actual
stratejilerin şunları yapabileceğini unutmayın:
Oda ile ilgili tanımları aşamalı olarak taşımak için kullanılır. Örneğin tüm
askıya alınan DAO işlevlerinin askıya alınmasıyla ilgili işlevler, askıya alma işlevlerine
ortak kodda boş olan bir expect
@Dao
ek açıklamalı arayüzü bildirir, ancak
Android'de engelleme işlevleri içerir.
// shared/src/commonMain/kotlin/Database.kt
@Database(entities = [TodoEntity::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun getDao(): TodoDao
abstract fun getBlockingDao(): BlockingTodoDao
}
@Dao
interface TodoDao {
@Query("SELECT count(*) FROM TodoEntity")
suspend fun count(): Int
}
@Dao
expect interface BlockingTodoDao
// shared/src/androidMain/kotlin/BlockingTodoDao.kt
@Dao
actual interface BlockingTodoDao {
@Query("SELECT count(*) FROM TodoEntity")
fun count(): Int
}