توفر مكتبة بقاء الغرفة طبقة تجريدية فوق SQLite للسماح للوصول بفعالية أكبر إلى قاعدة البيانات مع الاستفادة من الإمكانيات الكاملة لـ SQLite. هذا النمط على استخدام الغرف في مشروعات Kotlin متعددة الأنظمة الأساسية (KMP). لمزيد من المعلومات، معلومات حول استخدام الغرفة، يُرجى الاطّلاع على حفظ البيانات في قاعدة بيانات محلية باستخدام الغرفة. أو عيّنات رسمية
إعداد التبعيات
إنّ إصدار الغرفة الحالي الذي يتوافق مع "منصّة KMP" هو 2.7.0-alpha01 أو أعلى.
لإعداد غرفة في مشروع KMP، أضِف التبعيات للعناصر في
ملف واحد (build.gradle.kts
) للوحدة:
androidx.room:room-gradle-plugin
- مكوّن Gradle الإضافي لإعداد مخططات الغرفandroidx.room:room-compiler
- معالج KSP الذي ينشئ الرمزandroidx.room:room-runtime
- جزء بيئة التشغيل في المكتبةandroidx.sqlite:sqlite-bundled
- (اختياري) مكتبة SQLite المجمّعة
بالإضافة إلى ذلك، عليك ضبط برنامج تشغيل SQLite في الغرفة. برامج التشغيل هذه مختلفة بناءً على النظام الأساسي المستهدف. عرض عمليات تنفيذ برامج التشغيل للحصول على أوصاف لعمليات تنفيذ برامج التشغيل المتاحة.
للحصول على معلومات إضافية عن الإعداد، يمكنك الاطّلاع على ما يلي:
- ضبط موقع المخطّط باستخدام المكوّن الإضافي لنظام Gradle المتوافق مع الغرف
- KSP باستخدام Kotlin Multiplatform.
- إضافة تبعيات بيئة التشغيل:
تحديد فئات قاعدة البيانات
يجب عليك إنشاء فئة قاعدة بيانات تتضمن تعليقات توضيحية باستخدام @Database
إلى جانب DAO.
والكيانات الموجودة ضمن مجموعة المصادر المشتركة في وحدة KMP المشتركة. جارٍ التقديم
هذه الفئات في المصادر المشتركة ستسمح بمشاركتها عبر كل الاستهداف
الأساسية.
عند التعريف عن كائن expect
باستخدام الواجهة
RoomDatabaseConstructor
، ينشئ برنامج تجميع الغرف actual
وعمليات التنفيذ. قد يُصدر "استوديو Android" تحذيرًا
"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
)
يُرجى العلم أنّه يمكنك اختياريًا استخدام الإعلانات الفعلية / المتوقَّعة.
لإنشاء عمليات تنفيذ غرف خاصة بالنظام الأساسي. على سبيل المثال، يمكنك إضافة
DAO الخاص بالنظام الأساسي والمحدد في التعليمات البرمجية المشتركة باستخدام expect
ثم
حدِّد تعريفات actual
باستخدام طلبات بحث إضافية في النظام الأساسي
مجموعات المصادر.
إنشاء منصة إنشاء قاعدة البيانات
تحتاج إلى تعريف أداة إنشاء قاعدة بيانات لإنشاء مثيل الغرفة على كل نظام أساسي. هذا النمط
هو الجزء الوحيد المطلوب من واجهة برمجة التطبيقات في مصدر خاص بالنظام الأساسي
بسبب الاختلافات في واجهات برمجة تطبيقات نظام الملفات. على سبيل المثال، في Android،
موقع قاعدة البيانات يتم الحصول عليه عادةً من خلال
Context.getDatabasePath()
API، في حين أن موقع قاعدة البيانات لنظام التشغيل 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
، بينما يمكنك استخدام NativeSQLiteDriver
على أجهزة iOS. إلى
تستخدم 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 مع التركيز على التوافق مع واجهة برمجة التطبيقات. يختلف إصدار KMP من الغرفة إلى حد ما بين الأنظمة الأساسية والإصدار الخاص بـ Android. وهذه الاختلافات هي وموضحة على النحو التالي.
حظر دوال DAO
عند استخدام Room لـ KMP، يتم تجميع جميع دوال DAO للأنظمة الأساسية غير Android
يجب أن تكون دوال 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
يتم فرض الدوال على أنظمة DAO التي تم تجميعها في مشروع KMP، باستثناء
أنظمة DAO الخاصة بنظام Android للحفاظ على التوافق مع الأنظمة القديمة
أو قاعدة التعليمات البرمجية.
الاختلافات في الميزات مع KMP
يوضّح هذا القسم أوجه اختلاف الميزات بين "منصة إدارة المحتوى" (KMP) ونظام Android الأساسي. من Google Room.
دوال @RawQuery DAO
الدوال التي تمت إضافة تعليقات توضيحية إليها باستخدام @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
باستخدام قاعدة بيانات حالية (أي
قاعدة البيانات المعبأة مسبقًا) غير متوفرة بشكل عام وبالتالي لا تتوفر في
الأنظمة الأساسية الأخرى بخلاف Android. واجهات برمجة التطبيقات هذه هي:
RoomDatabase.Builder.createFromAsset
RoomDatabase.Builder.createFromFile
RoomDatabase.Builder.createFromInputStream
RoomDatabase.PrepackagedDatabaseCallback
نعتزم إضافة دعم لقواعد البيانات المعبأة مسبقًا في إصدار مستقبلي من غرفة.
إبطال متعدِّد المثيلات
واجهة برمجة التطبيقات لتفعيل إلغاء المثيلات المتعددة،
RoomDatabase.Builder.enableMultiInstanceInvalidation
متوفر فقط على
Android ولا يتوفر في أنظمة التشغيل المشتركة أو الأنظمة الأساسية الأخرى.