کتابخانه تداوم اتاق یک لایه انتزاعی را بر روی SQLite فراهم می کند تا در عین استفاده از قدرت کامل SQLite، امکان دسترسی قوی تر به پایگاه داده را فراهم کند. این صفحه بر روی استفاده از اتاق در پروژههای چند پلتفرمی Kotlin (KMP) تمرکز دارد. برای اطلاعات بیشتر در مورد استفاده از اتاق، به ذخیره داده ها در پایگاه داده محلی با استفاده از اتاق یا نمونه های رسمی ما مراجعه کنید.
راه اندازی وابستگی ها
نسخه فعلی Room که از KMP پشتیبانی می کند 2.7.0-alpha01 یا بالاتر است.
برای راهاندازی Room در پروژه 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 اتاق را پیکربندی کنید. این درایورها بر اساس پلتفرم هدف متفاوت هستند. برای توضیحات پیاده سازی درایورهای موجود ، پیاده سازی درایور را ببینید.
برای اطلاعات بیشتر تنظیمات، به موارد زیر مراجعه کنید:
- با استفاده از پلاگین Room Gradle مکان طرح را تنظیم کنید .
- KSP با چند پلتفرم Kotlin .
- افزودن وابستگی های زمان اجرا
تعریف کلاس های پایگاه داده
شما باید یک کلاس پایگاه داده مشروح شده با @Database
همراه با DAO ها و موجودیت ها در داخل مجموعه منبع مشترک ماژول KMP مشترک خود ایجاد کنید. قرار دادن این کلاس ها در منابع مشترک به آنها اجازه می دهد تا در تمام پلتفرم های هدف به اشتراک گذاشته شوند.
هنگامی که یک شیء expect
با رابط RoomDatabaseConstructor
اعلام می کنید، کامپایلر Room پیاده سازی های 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
)
توجه داشته باشید که میتوانید به صورت اختیاری از اعلانهای واقعی / انتظاری برای ایجاد پیادهسازیهای اتاق مخصوص پلتفرم استفاده کنید. برای مثال، میتوانید یک DAO مخصوص پلتفرم را اضافه کنید که در کدهای رایج با استفاده از expect
تعریف شده است و سپس تعاریف actual
را با پرسوجوهای اضافی در مجموعههای منبع خاص پلتفرم مشخص کنید.
ایجاد سازنده پایگاه داده
برای نمونه سازی Room در هر پلتفرم باید یک سازنده پایگاه داده تعریف کنید. این تنها بخشی از API است که به دلیل تفاوت در API های سیستم فایل، باید در مجموعه های منبع خاص پلت فرم باشد. به عنوان مثال، در Android، مکان پایگاه داده معمولاً از طریق Context.getDatabasePath()
API به دست می آید، در حالی که برای iOS، مکان پایگاه داده با استفاده از NSFileManager
به دست می آید.
اندروید
برای ایجاد نمونه پایگاه داده، یک Context را به همراه مسیر پایگاه داده مشخص کنید.
// 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 API ارائه کنید.
// 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
API در مجموعههای منبع خاص پلتفرم که درایور مخصوص پلتفرم را مشخص میکنند، استفاده کنید. برای اندروید، میتوانید از 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")
}
}
}
تفاوت ها
Room در ابتدا به عنوان یک کتابخانه اندروید توسعه یافت و بعداً با تمرکز بر سازگاری API به KMP منتقل شد. نسخه KMP اتاق بین پلتفرمها و با نسخه مخصوص اندروید تا حدودی متفاوت است. این تفاوت ها به شرح زیر فهرست شده و شرح داده شده است.
مسدود کردن توابع DAO
هنگام استفاده از Room for KMP، همه توابع DAO که برای پلتفرمهای غیر اندرویدی کامپایل شدهاند، باید توابع 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 های خاص اندروید برای حفظ سازگاری با پایگاه کد موجود، اعمال می شوند.
تفاوت ویژگی ها با KMP
این بخش چگونگی تفاوت ویژگیها را بین نسخههای اتاق سیستم عامل KMP و Android توضیح میدهد.
توابع @RawQuery DAO
توابع حاشیه نویسی شده با @RawQuery
که برای پلتفرم های غیر اندرویدی کامپایل شده اند باید به جای SupportSQLiteQuery
پارامتری از نوع RoomRawQuery
را اعلام کنند.
@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)
}
درخواست پاسخ به تماس
APIهای زیر برای پیکربندی پاسخهای درخواستی به طور مشترک در دسترس نیستند و بنابراین در پلتفرمهایی غیر از Android در دسترس نیستند.
-
RoomDatabase.Builder.setQueryCallback
-
RoomDatabase.QueryCallback
ما در نظر داریم در نسخه آینده اتاق، پشتیبانی از پاسخ به درخواست را اضافه کنیم.
API برای پیکربندی RoomDatabase
با درخواست پاسخ به تماس RoomDatabase.Builder.setQueryCallback
همراه با واسط callback RoomDatabase.QueryCallback
به طور مشترک در دسترس نیستند و بنابراین در پلتفرم های دیگر غیر از Android در دسترس نیستند.
بسته شدن خودکار پایگاه داده
API برای فعال کردن بسته شدن خودکار پس از مهلت زمانی، RoomDatabase.Builder.setAutoCloseTimeout
، فقط در Android در دسترس است و در سایر سیستم عامل ها در دسترس نیست.
پایگاه داده پیش بسته
APIهای زیر برای ایجاد یک RoomDatabase
با استفاده از یک پایگاه داده موجود (یعنی یک پایگاه داده از پیش بسته بندی شده) مشترک نیستند و بنابراین در پلتفرم های دیگر غیر از Android در دسترس نیستند. این APIها عبارتند از:
-
RoomDatabase.Builder.createFromAsset
-
RoomDatabase.Builder.createFromFile
-
RoomDatabase.Builder.createFromInputStream
-
RoomDatabase.PrepackagedDatabaseCallback
ما قصد داریم در نسخه بعدی Room پشتیبانی از پایگاه های داده از پیش بسته بندی شده را اضافه کنیم.
بی اعتباری چند موردی
API برای فعال کردن باطلسازی چند نمونهای، RoomDatabase.Builder.enableMultiInstanceInvalidation
فقط در Android در دسترس است و در پلتفرمهای رایج یا دیگر در دسترس نیست.