Oda (Kotlin Multiplatform)

Oda kalıcılık kitaplığı, izin vermek için SQLite üzerinde bir soyutlama katmanı sağlar ile daha güçlü veritabanı erişimi sunar ve SQLite'ın tam gücünden yararlanır. Bu Bu sayfada, Kotlin Multiplatform (KMP) projelerinde Room'un kullanımıyla ilgili bilgiler yer almaktadır. Daha fazla Odayı kullanmayla ilgili daha fazla bilgi için Odayı kullanarak verileri yerel veritabanına kaydetme başlıklı makaleye göz atın. veya resmi örneklerimizi kullanın.

Bağımlılıkları belirleme

Odanın KMP'yi destekleyen mevcut sürümü: 2.7.0-alpha01 veya sonraki sürümler.

KMP projenizde Room (Oda) ayarlarını yapmak için Modülünüz için build.gradle.kts dosyası:

  • androidx.room:room-gradle-plugin - Oda şemalarını yapılandırmak için Gradle Eklentisi
  • androidx.room:room-compiler - Kod oluşturan KSP işlemcisi
  • androidx.room:room-runtime - Kitaplığın çalışma zamanı bölümü
  • androidx.sqlite:sqlite-bundled - (İsteğe bağlı) Paket halinde sunulan SQLite kitaplığı

Ayrıca, Odanın SQLite sürücüsünü yapılandırmanız gerekir. Bu sürücüler farklı tercih edebilirsiniz. Görüntüleyin Sürücü uygulamaları inceleyebilirsiniz.

Ek kurulum bilgileri için aşağıdakilere bakın:

ziyaret edin.

Veritabanı sınıflarını tanımlama

DAO'larla birlikte @Database ek açıklamalı bir veritabanı sınıfı oluşturmanız gerekir. ve ortak KMP modülünüzün ortak kaynak kümesindeki varlıklar için geçerlidir. Yerleştirme ortak kaynaklarda yer alan bu sınıflar, tüm hedeflerde paylaşılmasına olanak tanır. platformlar.

Arayüzde expect nesnesi belirttiğinizde RoomDatabaseConstructor, Oda derleyicisi actual oluşturur hakkında bilgi edindiniz. Android Studio bir uyarı gönderebilir "Expected object 'AppDatabaseConstructor' has no actual declaration in module"; uyarıyı @Suppress("NO_ACTUAL_FOR_EXPECT") ile gizleyebilirsiniz.

// 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> {
    override fun initialize(): 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
)

İsterseniz gerçek / beklenen beyanları da kullanabilirsiniz. oda uygulamaları oluşturabilirsiniz. Örneğin, Arkadaş Bitkiler uygulamasına bir expect ve ardından kullanılarak ortak kodda tanımlanan platforma özel DAO platforma özgü ek sorgularla birlikte actual tanımlarını belirtin kaynak kümeleridir.

Veritabanı oluşturucuyu oluşturma

Her platformda Oda örneğini oluşturmak için bir veritabanı oluşturucu tanımlamanız gerekir. Bu API'nin platforma özgü kaynakta olması gereken tek bölümüdür farklı kümelere sahip URL'ler oluşturabilirsiniz. Örneğin, Android'de konum bilgisi genellikle Context.getDatabasePath() API, iOS'te ise veritabanı konumu şöyledir: NSFileManager kullanılarak elde edilebilir.

Android

Veritabanı örneğini oluşturmak için veritabanıyla birlikte bir Bağlam bilgisi belirtin yol'a dokunun.

// 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

Veritabanı örneğini oluşturmak için NSFileManager, genellikle NSDocumentDirectory konumunda bulunur.

// 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 (Masaüstü)

Veritabanı örneği oluşturmak için Java veya Kotlin kullanarak veritabanı yolu sağlayın API'ler.

// 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,
    )
}

Veritabanı örneklendirmesi

Platforma özgü uygulamaların birinden RoomDatabase.Builder aldıktan sonra varsa, Room veritabanının geri kalanını ortak bir kodda örneklemlendirme ile birlikte kullanabilirsiniz.

// 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 Seçme

Önceki kod snippet'leri BundledSQLiteDriver kullanıyor. Bu, Kaynaktan derlenen SQLite'ı içeren önerilen sürücüyü tüm platformlarda SQLite'ın en tutarlı ve güncel sürümünü sunar. Şu durumda: işletim sistemi tarafından sağlanan SQLite'ı kullanmak istiyorsanız setDriver API'yi platforma özel olarak kullanın kaynak kümeleridir. Android'de, AndroidSQLiteDriver, iOS'te NativeSQLiteDriver kullanabilirsiniz. Alıcı: NativeSQLiteDriver kullanıyorsanız iOS'in değiştirebilmesi için bir bağlayıcı seçeneği SQLit sistemine dinamik olarak bağlanır.

// 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")
        }
    }
}

Farklılıklar

Oda, ilk başta bir Android kitaplığı olarak geliştirilmiş ve daha sonra API uyumluluğuna odaklanan KMP. Room'un KMP sürümü biraz farklıdır. Android'e özel sürümden fark etmiyor. Bu farklılıklar aşağıda açıklandığı gibi listelenip açıklaması gerekir.

DAO işlevlerini engelleme

Room for KMP kullanılırken Android dışı platformlar için derlenen tüm DAO işlevleri şunun reaktif dönüş türleri hariç olmak üzere suspend işlevleri olması gerekir: Flow olarak.

// 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() { // … }
}

Zengin özelliklere sahip eşzamansız kotlinx.coroutines kitaplığının sunduğu avantajlar üç platforma ulaşabilirsiniz. Optimum işlevsellik için suspend işlevleri hariç olmak üzere, KMP projesinde derlenen DAO'lar için Mevcut kullanabilirsiniz.

KMP ile özellik farklılıkları

Bu bölümde, KMP ve Android platformu arasındaki özelliklerin farkı açıklanmaktadır. oda sürümleridir.

@RawQuery DAO işlevleri

Android dışı platformlar için derlenen, @RawQuery ile ek açıklama eklenen işlevler yerine RoomRawQuery türünde bir parametre tanımlaması gerekir SupportSQLiteQuery.

@Dao
interface TodoDao {
  @RawQuery
  suspend fun getTodos(query RoomRawQuery): List<TodoEntity>
}

Çalışma zamanında sorgu oluşturmak için RoomRawQuery kullanılabilir:

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)
}

Sorgu Geri Çağırması

Sorgu geri çağırmalarının yapılandırılmasına yönelik aşağıdaki API'ler, yaygın olarak kullanılmamaktadır ve Android dışındaki platformlarda kullanılamaz.

  • RoomDatabase.Builder.setQueryCallback
  • RoomDatabase.QueryCallback

Odanın gelecekteki bir sürümünde geri arama için destek sunmayı planlıyoruz.

Sorgu geri çağırma özelliğiyle RoomDatabase yapılandırma API'si Geri çağırma arayüzüyle birlikte RoomDatabase.Builder.setQueryCallback RoomDatabase.QueryCallback ortak olarak kullanılamadığı için kullanılamıyor diğer platformlarda da kullanılabilir.

Veritabanını Otomatik Kapatma

Zaman aşımından sonra otomatik kapanmayı etkinleştiren API, RoomDatabase.Builder.setAutoCloseTimeout yalnızca Android'de kullanılabilir ve diğer platformlarda kullanılamıyor.

Önceden Paketlenmiş Veritabanı

Mevcut bir veritabanını (ör.RoomDatabase veri tabanı) ortak olarak mevcut değildir ve bu nedenle Android dışındaki platformlarda çalışabilirsiniz. Bu API'ler şunlardır:

  • RoomDatabase.Builder.createFromAsset
  • RoomDatabase.Builder.createFromFile
  • RoomDatabase.Builder.createFromInputStream
  • RoomDatabase.PrepackagedDatabaseCallback

Gelecekteki bir sürüme, kullanıma hazır veritabanları için destek sunmayı planlıyoruz Oda.

Çoklu Örnek Geçersiz Kılma

Çoklu örneği geçersiz kılmayı sağlayan API, RoomDatabase.Builder.enableMultiInstanceInvalidation şuralarda kullanılabilir: Android'dir ve yaygın olarak veya diğer platformlarda kullanılamaz.