Room 3.0 is a major version update that transitions the library to be Kotlin-first. It supports Kotlin Multiplatform (KMP), requires Kotlin Symbol Processing (KSP), and enforces coroutines for asynchronous operations.
برای جلوگیری از مشکلات سازگاری با برنامههای 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
Before migrating to Room 3.0, you can perform most modernization work by updating to the current Room 2.x release, like Room 2.8. Room 2.8 supports Kotlin Multiplatform, or KMP, and includes many driver APIs that Room 3.0 uses.
به اتاق ۲.۸ و بالاتر ارتقا دهید
پیکربندی ساخت خود را برای استفاده از نسخه فعلی 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های اصلی خود پشتیبانی نمیکند.
If you don't call setDriver to set a SQLiteDriver on your database builder, Room 2.8 operates in a compatibility mode where both Support SQLite and Driver APIs function. This compatibility mode lets you incrementally convert your codebase before enabling the driver.
- تبدیل مهاجرتها : زیرکلاسهای
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که فقط برای اندروید هستند را باwithWriteTransactionیاwithReadTransactionجایگزین کنید:
// Before (withTransaction)
db.withTransaction {
// perform database operations
}
// After (withWriteTransaction - Room 2.8)
import androidx.room.withWriteTransaction
db.withWriteTransaction {
// perform database operations
}
اگر به دسترسی مستقیم سطح پایین به اتصال تراکنش نیاز دارید، میتوانید useWriterConnection به همراه immediateTransaction نیز استفاده کنید.
- Avoid direct usage of
SupportSQLiteDatabase: If you have extensive legacy code that still requiresSupportSQLiteDatabaseand you can't migrate it yet, use theandroidx.room:room-sqlite-wrappercompatibility artifact:
dependencies {
implementation("androidx.room:room-sqlite-wrapper:$roomVersion")
}
و سپس، getSupportWrapper برای دریافت SupportSQLiteDatabase از نمونه پایگاه داده Room خود استفاده کنید:
import androidx.room.support.getSupportWrapper
val legacyDb: SupportSQLiteDatabase = roomDatabase.getSupportWrapper()
- Set the SQLite driver : After you migrate all Room API usages to driver APIs, configure a driver, like
BundledSQLiteDriverorAndroidSQLiteDriver, by callingsetDriverin yourRoomDatabasebuilder:
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
val db = Room.databaseBuilder<AppDatabase>(context, "db")
.setDriver(BundledSQLiteDriver())
.build()
ردیابی ابطال مبتنی بر جریان را اتخاذ کنید
Room 2.8 introduces the InvalidationTracker.createFlow API. Use this API to migrate away from legacy InvalidationTracker.Observer implementations while still on Room 2.x. This prepares your codebase for Room 3.0, which completely removes 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()
}