रूम (Kotlin मल्टीप्लैटफ़ॉर्म)

रूम परसिस्टेंस लाइब्रेरी, SQLite पर एक ऐब्स्ट्रक्शन लेयर उपलब्ध कराती है, ताकि ताकि SQLite की पूरी क्षमता का इस्तेमाल किया जा सके और डेटाबेस को ज़्यादा बेहतर तरीके से ऐक्सेस किया जा सके. यह यह पेज, Kotlin Multiplatform (KMP) प्रोजेक्ट में रूम के इस्तेमाल पर फ़ोकस करता है. ज़्यादा के लिए रूम का इस्तेमाल करने के बारे में जानकारी, रूम का इस्तेमाल करके स्थानीय डेटाबेस में डेटा सेव करना देखें या हमारे आधिकारिक सैंपल.

डिपेंडेंसी सेट अप करना

रूम का मौजूदा वर्शन जो केएमपी पर काम करता है यह है 2.7.0-alpha01 या इसके बाद का वर्शन.

अपने केएमपी प्रोजेक्ट में रूम सेटअप करने के लिए, build.gradle.kts फ़ाइल:

  • androidx.room:room-gradle-plugin - रूम स्कीमा को कॉन्फ़िगर करने के लिए Gradle प्लग इन
  • androidx.room:room-compiler - KSP का प्रोसेसर, जो कोड जनरेट करता है
  • androidx.room:room-runtime - लाइब्रेरी का रनटाइम हिस्सा
  • androidx.sqlite:sqlite-bundled - (ज़रूरी नहीं) बंडल की गई SQLite लाइब्रेरी

इसके अलावा, आपको रूम का SQLite ड्राइवर कॉन्फ़िगर करना होगा. ये ड्राइवर अलग-अलग होते हैं टारगेट प्लैटफ़ॉर्म के हिसाब से तय किया जाता है. यहां जाएं: Driver लागू करना देखें.

सेटअप से जुड़ी अतिरिक्त जानकारी के लिए, इन्हें देखें:

डेटाबेस क्लास के बारे में जानकारी

आपको डीएओ के साथ-साथ, @Database से जुड़ी जानकारी देने वाली डेटाबेस क्लास बनानी होगी और इकाइयां, जो आपके शेयर किए गए केएमपी मॉड्यूल के कॉमन सोर्स सेट में मौजूद हैं. स्थान ये क्लास सामान्य सोर्स में मौजूद हैं. इन्हें सभी टारगेट के लिए शेयर किया जा सकेगा प्लैटफ़ॉर्म.

जब इंटरफ़ेस की मदद से, expect ऑब्जेक्ट का एलान किया जाता है RoomDatabaseConstructor, रूम कंपाइलर actual जनरेट करता है लागू करना. Android Studio चेतावनी जारी कर सकता है "Expected object 'AppDatabaseConstructor' has no actual declaration in module"; आप @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> {
    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
)

ध्यान दें कि आपके पास असल / किए गए एलानों का इस्तेमाल करने का विकल्प होता है अलग-अलग प्लैटफ़ॉर्म के हिसाब से रूम लागू करने के लिए. उदाहरण के लिए, आप प्लैटफ़ॉर्म के हिसाब से डीएओ, जिसे expect का इस्तेमाल करके सामान्य कोड में तय किया जाता है. इसके बाद प्लैटफ़ॉर्म के हिसाब से, अन्य क्वेरी के साथ actual की परिभाषाएं बताता है सोर्स सेट का इस्तेमाल करें.

डेटाबेस बिल्डर बनाना

हर प्लैटफ़ॉर्म पर रूम को इंस्टैंशिएट करने के लिए, आपको डेटाबेस बिल्डर तय करना होगा. यह एपीआई का सिर्फ़ एक हिस्सा है, जिसका प्लैटफ़ॉर्म के हिसाब से सोर्स में होना ज़रूरी है सेट हैं. उदाहरण के लिए, Android में, डेटाबेस की लोकेशन को आम तौर पर Context.getDatabasePath() एपीआई, जबकि iOS के लिए डेटाबेस की लोकेशन पाने के लिए NSFileManager का इस्तेमाल करें.

Android

डेटाबेस इंस्टेंस बनाने के लिए, डेटाबेस के साथ कॉन्टेक्स्ट तय करें पाथ.

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

डेटाबेस इंस्टेंस बनाने के लिए, इसका इस्तेमाल करके डेटाबेस पाथ दें NSFileManager, आम तौर पर 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 (डेस्कटॉप)

डेटाबेस इंस्टेंस बनाने के लिए, Java या Kotlin का इस्तेमाल करके डेटाबेस का पाथ दें एपीआई.

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

डेटाबेस इंस्टैंशिएट करना

आपको किसी खास प्लैटफ़ॉर्म से RoomDatabase.Builder मिलने के बाद कंस्ट्रक्टर के तौर पर, आपके पास रूम के बाकी डेटाबेस को कॉमन कोड में कॉन्फ़िगर करने की सुविधा होती है के साथ-साथ.

// 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 चुनना

पिछले कोड स्निपेट, BundledSQLiteDriver का इस्तेमाल करते हैं. यह है सुझाया गया ड्राइवर जिसमें सोर्स से इकट्ठा की गई SQLite शामिल है, जो सभी प्लैटफ़ॉर्म पर SQLite का सबसे सटीक और अप-टू-डेट वर्शन होना चाहिए. अगर आपको अगर आपको ओएस से मिलने वाले SQLite का इस्तेमाल करना है, तो प्लैटफ़ॉर्म के हिसाब से setDriver एपीआई का इस्तेमाल करें जो प्लैटफ़ॉर्म के हिसाब से ड्राइवर तय करते हैं. Android के लिए AndroidSQLiteDriver, जबकि iOS के लिए NativeSQLiteDriver का इस्तेमाल किया जा सकता है. यहां की यात्रा पर हूं NativeSQLiteDriver का इस्तेमाल करते हैं, तो आपको लिंकर विकल्प देना होगा, ताकि iOS ऐप्लिकेशन, सिस्टम 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")
        }
    }
}

अंतर

रूम को मूल रूप से Android लाइब्रेरी के तौर पर बनाया गया था और बाद में एपीआई के साथ काम करने की सुविधा पर फ़ोकस करने वाली KMP. Room का KMP वर्शन कुछ हद तक अलग है अलग-अलग प्लैटफ़ॉर्म के बीच तुलना करता है. ये अंतर नीचे दिए गए निर्देशों का पालन करें.

डीएओ फ़ंक्शन को ब्लॉक करना

केएमपी के लिए रूम का इस्तेमाल करते समय, Android के अलावा अन्य प्लैटफ़ॉर्म के लिए इकट्ठा किए गए सभी डीएओ फ़ंक्शन reऐक्टिव रिटर्न टाइप को छोड़कर, suspend फ़ंक्शन होने चाहिए, जैसे कि 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() { // … }
}

बेहतरीन एसिंक्रोनस kotlinx.coroutines लाइब्रेरी का इस्तेमाल करके, कमरे के फ़ायदे जो Kotlin की मदद से कई प्लैटफ़ॉर्म को ऑफ़र करती है. बेहतर तरीके से काम करने के लिए, suspend केएमपी प्रोजेक्ट में इकट्ठा किए गए डीएओ के लिए, फ़ंक्शन लागू किए जाते हैं. हालांकि, अपवाद के तौर पर ये सुविधाएं लागू नहीं होती हैं Android के लिए खास डीएओ, जिन्हें मौजूदा वर्शन के साथ पुराने सिस्टम के साथ काम करने की सुविधा को बनाए रखने के लिए इस्तेमाल किया जाता है कोड बेस में एक्सपोर्ट करें.

केएमपी की सुविधाओं में अंतर

इस सेक्शन में बताया गया है कि KMP और Android प्लैटफ़ॉर्म के लिए सुविधाएं किस तरह से अलग हैं रूम के वर्शन उपलब्ध हैं.

@RawQuery डीएओ फ़ंक्शन

@RawQuery के साथ एनोटेट किए गए ऐसे फ़ंक्शन जिन्हें Android के अलावा, दूसरे प्लैटफ़ॉर्म के लिए इकट्ठा किया जाता है इसके बजाय, RoomRawQuery टाइप का पैरामीटर बताने की ज़रूरत होगी SupportSQLiteQuery.

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

इसके बाद, रनटाइम के दौरान क्वेरी बनाने के लिए RoomRawQuery का इस्तेमाल किया जा सकता है:

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

क्वेरी कॉलबैक

क्वेरी कॉलबैक कॉन्फ़िगर करने के लिए, ये एपीआई सामान्य तौर पर उपलब्ध नहीं हैं इसलिए, यह सुविधा Android के अलावा, किसी भी अन्य प्लैटफ़ॉर्म पर उपलब्ध नहीं है.

  • RoomDatabase.Builder.setQueryCallback
  • RoomDatabase.QueryCallback

हम रूम के आने वाले वर्शन में, क्वेरी कॉलबैक के लिए सहायता जोड़ना चाहते हैं.

क्वेरी कॉलबैक के साथ RoomDatabase को कॉन्फ़िगर करने का एपीआई कॉलबैक इंटरफ़ेस के साथ RoomDatabase.Builder.setQueryCallback RoomDatabase.QueryCallback समान रूप से उपलब्ध नहीं हैं और इसलिए उपलब्ध नहीं हैं Android के अलावा, अन्य प्लैटफ़ॉर्म पर लागू होते हैं.

अपने-आप बंद होने का डेटाबेस

एक टाइम आउट के बाद, अपने-आप बंद होने की सुविधा चालू करने वाला एपीआई, RoomDatabase.Builder.setAutoCloseTimeout, सिर्फ़ Android पर उपलब्ध है और अन्य प्लैटफ़ॉर्म में उपलब्ध नहीं है.

प्री-पैकेज डेटाबेस

मौजूदा डेटाबेस का इस्तेमाल करके RoomDatabase बनाने के लिए, नीचे दिए गए एपीआई (जैसे कि प्री-पैकेज्ड डेटाबेस) समान रूप से उपलब्ध नहीं हैं और इसलिए की सुविधा मिलती है. ये एपीआई हैं:

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

हम पहले से पैकेज किए गए डेटाबेस के लिए समर्थन को इसके भविष्य के वर्शन में जोड़ना चाहते हैं कमरा.

एक से ज़्यादा इंस्टेंस अमान्य करना

एक से ज़्यादा इंस्टेंस अमान्य होने की सुविधा को चालू करने के लिए एपीआई, RoomDatabase.Builder.enableMultiInstanceInvalidation सिर्फ़ यहां उपलब्ध है Android, आम तौर पर इस्तेमाल किए जाने वाले या किसी दूसरे प्लैटफ़ॉर्म पर उपलब्ध नहीं है.