Room 3.0 یک بهروزرسانی عمده نسخه است که کتابخانه را به Kotlin-first منتقل میکند. این کتابخانه از Kotlin Multiplatform (KMP) پشتیبانی میکند، به Kotlin Symbol Processing (KSP) نیاز دارد و Coroutineها را برای عملیات ناهمزمان اعمال میکند.
برای جلوگیری از مشکلات سازگاری با برنامههای Room 2.x موجود و وابستگیهای انتقالی، Room 3.0 در یک بسته جدید قرار دارد: androidx.room3 .
این راهنما مراحل لازم برای انتقال پیادهسازی Room 2.x موجود شما به Room 3.0 را شرح میدهد.
تغییرات کلیدی در اتاق ۳.۰
قبل از شروع مهاجرت، با تفاوتهای اصلی آشنا شوید:
- بسته و مصنوعات جدید : همه کلاسها در
androidx.room3قرار دارند. مصنوعات از پیشوندroom3استفاده میکنند، مانندandroidx.room3:room3-runtime. - فقط Kotlin و KSP : Room 3.0 از تولید کد جاوا پشتیبانی نمیکند. به جای KAPT یا پردازندههای حاشیهنویسی جاوا از KSP استفاده کنید. Room 3.0 همچنان از منابع جاوا به عنوان ورودی پشتیبانی میکند.
- Coroutine first : توابع DAO باید توابع
suspendباشند، به جز انواع observable.CoroutineContextجایگزین executorها میشود. - بدون SupportSQLite : رابطهای برنامهنویسی
SQLiteDriverRoom را پشتیبانی میکنند. Room،SupportSQLiteDatabaseاز رابطهای برنامهنویسی اصلی حذف میکند. - تغییرات API : مهاجرتها و فراخوانیهای پایگاه داده به جای
SupportSQLiteDatabaseازSQLiteConnectionاستفاده میکنند. - مبدلها برای انواع واکنشی : انواع بازگشتی RxJava، LiveData، Guava و Paging نیاز دارند که شما
@DaoReturnTypeConvertersرا ثبت کنید.
ما توصیه میکنیم مهاجرت را در دو مرحله مجزا انجام دهید: ابتدا آمادهسازی و مدرنسازی پایگاه کد خود در Room 2.x و سپس انتقال به Room 3.0.
آمادهسازی و نوسازی در اتاق ۲.x
قبل از مهاجرت به Room 3.0، میتوانید بیشتر کارهای مدرنسازی را با بهروزرسانی به نسخه فعلی Room 2.x، مانند Room 2.8، انجام دهید. Room 2.8 از Kotlin Multiplatform یا KMP پشتیبانی میکند و شامل بسیاری از APIهای درایور است که Room 3.0 از آنها استفاده میکند.
به اتاق ۲.۸ و بالاتر ارتقا دهید
پیکربندی ساخت خود را برای استفاده از نسخه فعلی Room 2.x بهروزرسانی کنید:
[versions]
room2 = "2.8.4" # Use the current Room 2.8 version
[libraries]
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room2" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room2" }
مهاجرت از KAPT به KSP
روم ۳.۰ از پردازندههای حاشیهنویسی جاوا یا KAPT پشتیبانی نمیکند. شما باید از پردازش نمادهای کاتلین (KSP) استفاده کنید. میتوانید این انتقال را در حالی که هنوز در روم ۲.x هستید، انجام دهید.
در
build.gradle.ktsماژول خود، افزونه KSP را اعمال کنید:plugins { id("com.google.devtools.ksp") version "<ksp_version>" }مطمئن شوید که نسخه KSP با نسخه کاتلین شما سازگار است.
برای وابستگی کامپایلر Room
kaptیاannotationProcessorرا باkspجایگزین کنید:dependencies { implementation(libs.androidx.room.runtime) ksp(libs.androidx.room.compiler) }
کوروتینها را بپذیرید
اتاق ۳.۰ برای عملیات ناهمزمان به کوروتین نیاز دارد.
- بهروزرسانی DAOهای خود: مگر اینکه یک نوع واکنشی قابل مشاهده، مانند انواع
Flowیا RxJava، را برگردانند، تمام توابع DAO باید توابعsuspendباشند.
// Before (Blocking)
@Dao
interface UserDao {
@Query("SELECT * FROM User")
fun getAll(): List<User>
}
// After (Suspend)
@Dao
interface UserDao {
@Query("SELECT * FROM User")
suspend fun getAll(): List<User>
}
- اگر
RoomDatabaseخود را با یکExecutorسفارشی برای انجام عملیات پایگاه داده پیکربندی کردهاید، با استفاده ازsetQueryCoroutineContextدر سازنده، بهCoroutineContextمهاجرت کنید:
Room.databaseBuilder<AppDatabase>(context, "db")
.setQueryCoroutineContext(Dispatchers.IO)
.build()
API های درایور را اتخاذ کنید و از پشتیبانی SQLite خودداری کنید
روم ۳.۰ به طور کامل توسط SQLiteDriver پشتیبانی میشود و دیگر SupportSQLiteDatabase در APIهای اصلی خود پشتیبانی نمیکند.
اگر برای تنظیم SQLiteDriver در سازنده پایگاه داده خود، setDriver فراخوانی نکنید، Room 2.8 در حالت سازگاری عمل میکند که در آن هم از SQLite پشتیبانی میکند و هم از APIهای درایور. این حالت سازگاری به شما امکان میدهد قبل از فعال کردن درایور، کدبیس خود را به صورت تدریجی تبدیل کنید.
- تبدیل مهاجرتها : زیرکلاسهای
MigrationوAutoMigrationSpecخود را طوری مهاجرت دهید که به جایSupportSQLiteDatabaseازSQLiteConnectionاستفاده کنند.
// Before (SupportSQLiteDatabase)
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL")
}
}
// After (SQLiteConnection - Room 2.8)
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.execSQL
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(connection: SQLiteConnection) {
connection.execSQL(
"ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL"
)
}
}
- تبدیل فراخوانیهای پایگاه داده : پیادهسازیهای
RoomDatabase.Callbackرا برای استفاده ازSQLiteConnectionبهروزرسانی کنید:
// Before (SupportSQLiteDatabase)
val callback = object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
// ...
}
}
// After (SQLiteConnection - Room 2.8)
val callback = object : RoomDatabase.Callback() {
override fun onCreate(connection: SQLiteConnection) {
// ...
}
}
- تبدیل توابع DAO
@RawQuery: برای توابعی که با@RawQueryحاشیهنویسی شدهاند، به جایSupportSQLiteQueryازRoomRawQueryاستفاده کنید:
// Before (SupportSQLiteQuery)
@Dao
interface UserDao {
@RawQuery
fun getUser(query: SupportSQLiteQuery): User
}
// After (RoomRawQuery)
@Dao
interface UserDao {
@RawQuery
suspend fun getUser(query: RoomRawQuery): User
}
شما میتوانید یک RoomRawQuery در زمان اجرا بسازید:
val query = RoomRawQuery(
sql = "SELECT * FROM User WHERE id = ?",
onBindStatement = { statement ->
statement.bindInt(1, userId)
}
)
- تبدیل APIهای تراکنش : بلوکهای
withTransactionوrunInTransactionکه فقط برای اندروید هستند را باuseWriterConnectionوimmediateTransactionجایگزین کنید:
// Before (withTransaction)
db.withTransaction {
// perform database operations
}
// After (useWriterConnection - Room 2.8)
import androidx.room.useWriterConnection
import androidx.room.immediateTransaction
db.useWriterConnection { connection ->
connection.immediateTransaction {
// perform database operations
}
}
- از استفاده مستقیم از
SupportSQLiteDatabaseخودداری کنید : اگر کد قدیمی گستردهای دارید که هنوز بهSupportSQLiteDatabaseنیاز دارد و هنوز نمیتوانید آن را منتقل کنید، از مصنوع سازگاریandroidx.room:room-sqlite-wrapperاستفاده کنید:
dependencies {
implementation("androidx.room:room-sqlite-wrapper:$roomVersion")
}
و سپس، getSupportWrapper برای دریافت SupportSQLiteDatabase از نمونه پایگاه داده Room خود استفاده کنید:
import androidx.room.support.getSupportWrapper
val legacyDb: SupportSQLiteDatabase = roomDatabase.getSupportWrapper()
- تنظیم درایور SQLite : پس از اینکه تمام کاربردهای API اتاق را به APIهای درایور منتقل کردید، با فراخوانی
setDriverدر سازندهRoomDatabaseخود، یک درایور مانندBundledSQLiteDriverیاAndroidSQLiteDriverرا پیکربندی کنید:
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
val db = Room.databaseBuilder<AppDatabase>(context, "db")
.setDriver(BundledSQLiteDriver())
.build()
ردیابی ابطال مبتنی بر جریان را اتخاذ کنید
اتاق ۲.۸ رابط برنامهنویسی کاربردی (API) InvalidationTracker.createFlow را معرفی میکند. از این API برای مهاجرت از پیادهسازیهای قدیمی InvalidationTracker.Observer در حالی که هنوز در اتاق ۲.x هستید، استفاده کنید. این کار کدبیس شما را برای اتاق ۳.۰ آماده میکند که به طور کامل Observer حذف میکند.
// Before (InvalidationTracker.Observer)
val observer = object : InvalidationTracker.Observer("User") {
override fun onInvalidated(tables: Set<String>) {
// reload user data
}
}
db.invalidationTracker.addObserver(observer)
// After (createFlow - Room 2.8)
val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
userDao.getAllUsers()
}
مهاجرت به اتاق ۳.۰
زمانی که برنامه خود را در Room 2.x مدرن کردید، انتقال به Room 3.0 شامل بهروزرسانی وابستگیها، وارد کردن بستهها و فراخوانیهای پایگاه داده میشود.
بهروزرسانی وابستگیها و وارد کردن بستهها
- در پیکربندی ساخت خود، وابستگیهای
androidx.roomرا باandroidx.room3جایگزین کنید:
[versions]
room3 = "3.0.0" # Use the current Room 3.0 version
[libraries]
androidx-room3-runtime = { module = "androidx.room3:room3-runtime", version.ref = "room3" }
androidx-room3-compiler = { module = "androidx.room3:room3-compiler", version.ref = "room3" }
- بلوک وابستگیهای خود را بهروزرسانی کنید:
dependencies {
implementation(libs.androidx.room3.runtime)
ksp(libs.androidx.room3.compiler)
}
- بستههای import خود را بهروزرسانی کنید.
import androidx.room.* را باimport androidx.room3.* جایگزین کنید.
بهروزرسانی APIهای مبدل نوع
اتاق ۳.۰ نام APIهای مبدل نوع را تغییر میدهد تا کاربرد آنها برای تبدیل مقادیر ستون را روشن کند و از سردرگمی با مبدلهای نوع بازگشتی DAO جلوگیری کند.
حاشیهنویسیها و توابع زیر را در کدبیس خود بهروزرسانی کنید:
- نام
@TypeConverterرا به@ColumnTypeConverterتغییر دهید. - نام
@TypeConvertersرا به@ColumnTypeConvertersتغییر دهید. - نام
@ProvidedTypeConverterرا به@ProvidedColumnTypeConverterتغییر دهید. - نام
RoomDatabase.Builder.addTypeConverterرا بهaddColumnTypeConverterتغییر دهید.
مثال:
// Before
@ProvidedTypeConverter
class Converters {
@TypeConverter
fun fromTimestamp(value: Long?): Date? = ...
}
@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase()
val db = Room.databaseBuilder<AppDatabase>(...)
.addTypeConverter(convertersInstance)
.build()
// After
import androidx.room3.ColumnTypeConverter
import androidx.room3.ColumnTypeConverters
import androidx.room3.ProvidedColumnTypeConverter
@ProvidedColumnTypeConverter
class Converters {
@ColumnTypeConverter
fun fromTimestamp(value: Long?): Date? = ...
}
@Database(entities = [User::class], version = 1)
@ColumnTypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase()
val db = Room.databaseBuilder<AppDatabase>(...)
.addColumnTypeConverter(convertersInstance)
.build()
بهروزرسانی فراخوانیهای برگشتی برای تعلیق توابع
در اتاق ۳.۰، فراخوانیهای پایگاه داده و مهاجرتها از SQLiteConnection استفاده میکنند و توابع suspend هستند.
- کلاسهای
Migrationدستی خود را بهروزرسانی کنید:
import androidx.sqlite.SQLiteConnection
import androidx.sqlite.async.executeSQL
val MIGRATION_1_2 = object : Migration(1, 2) {
override suspend fun migrate(connection: SQLiteConnection) {
connection.executeSQL(
"ALTER TABLE User ADD COLUMN age INTEGER DEFAULT 0 NOT NULL"
)
}
}
- پیادهسازیهای
RoomDatabase.Callbackخود را بهروزرسانی کنید:
val callback = object : RoomDatabase.Callback() {
override suspend fun onCreate(connection: SQLiteConnection) {
// ...
}
}
مبدلهای نوع بازگشتی DAO رجیستر
در اتاق ۳.۰، انواع برگشتی واکنشی، مانند RxJava، LiveData، Guava و Paging، شما را ملزم به ثبت مبدلهای نوع برگشتی DAO با استفاده از @DaoReturnTypeConverters میکنند.
import androidx.room3.paging.PagingSourceDaoReturnTypeConverter
@Dao
@DaoReturnTypeConverters(PagingSourceDaoReturnTypeConverter::class)
interface UserDao {
@Query("SELECT * FROM User")
fun getAllPaginated(): PagingSource<Int, User>
}
- صفحهبندی (
PagingSource) :PagingSourceDaoReturnTypeConverterرا از مصنوعandroidx.room3:room3-pagingثبت میکند. - RxJava(
Observable,Flowable,Single,Maybe,Completable) :RxDaoReturnTypeConvertersاز مصنوعandroidx.room3:room3-rxjava3ثبت میکند. - Guava (
ListenableFuture) :GuavaDaoReturnTypeConverterرا از مصنوعandroidx.room3:room3-guavaثبت میکند. - LiveData (
LiveData) : از روی مصنوعandroidx.room3:room3-livedataLiveDataDaoReturnTypeConverterرا ثبت کنید.
تأیید حذف ناظر InvalidationTracker
اتاق ۳.۰ به طور کامل InvalidationTracker.Observer و متدهای ثبت نام مرتبط، مانند addObserver و removeObserver حذف میکند.
اگر در فاز ۱ به جریانهای کوروتین منتقل نشدهاید، باید تمام کاربردهای Observer را به createFlow منتقل کنید:
val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
userDao.getAllUsers()
}