Room 3.0 یک بهروزرسانی نسخه عمده است که کتابخانه را به Kotlin-first منتقل میکند. این کتابخانه از Kotlin Multiplatform (KMP) پشتیبانی میکند، به Kotlin Symbol Processing (KSP) نیاز دارد، و برای عملیات ناهمگام از کوروتینها استفاده میکند.
برای جلوگیری از مشکلات سازگاری با برنامههای Room 2.x موجود و وابستگیهای گذرا، Room 3.0 در بسته جدیدی قرار دارد: androidx.room3.
این راهنما مراحل لازم برای انتقال پیادهسازی Room 2.x موجود به Room 3.0 را شرح میدهد.
تغییرات کلیدی در Room 3.0
قبلاز شروع انتقال، با تفاوتهای اصلی آشنا شوید:
- بسته و مصنوعات جدید: همه کلاسها در
androidx.room3قرار دارند. مصنوعات از پیشوندroom3استفاده میکنند، مثلandroidx.room3:room3-runtime. - فقط Kotlin و KSP: Room 3.0 از تولید کد Java پشتیبانی نمیکند. بهجای KAPT یا پردازشگرهای گزارمان Java، از KSP استفاده کنید. Room 3.0 همچنان از منابع Java بهعنوان ورودی پشتیبانی میکند.
- Coroutines first: DAO functions must be
suspendfunctions, except for observable types.CoroutineContextجایگزین مجریان میشود. - No SupportSQLite:
SQLiteDriverAPIs back Room. RoomSupportSQLiteDatabaseرا از میاناهای اصلی برمیدارد. - تغییرات میانای برنامهسازی کاربردی: انتقالها و فراخوانیهای پایگاه داده از
SQLiteConnectionبهجایSupportSQLiteDatabaseاستفاده میکنند. - تبدیلکنندهها برای انواع واکنشی: RxJava، LiveData، Guava، و Paging
انواع پاسخ نیاز دارند که
@DaoReturnTypeConvertersرا ثبت کنید.
توصیه میکنیم انتقال را در دو مرحله مجزا انجام دهید: ابتدا آمادهسازی و مدرنسازی پایگاه کد در Room 2.x، و سپس جابهجایی به Room 3.0.
آمادهسازی و مدرنسازی در Room 2.x
قبلاز انتقال به Room 3.0، میتوانید اکثر کارهای مدرنسازی را با بهروزرسانی به نسخه فعلی Room 2.x، مانند Room 2.8، انجام دهید. Room 2.8 از Kotlin Multiplatform (یا KMP) پشتیبانی میکند و شامل بسیاری از میاناهای برنامهسازی کاربردی درایور است که Room 3.0 از آنها استفاده میکند.
بهروزرسانی به Room نسخه ۲.۸ و بالاتر
پیکربندی ساخت خود را بهروز کنید تا از نسخه فعلی 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
Room 3.0 از پردازشگرهای گزارمان Java یا KAPT پشتیبانی نمیکند. باید از Kotlin Symbol Processing (KSP) استفاده کنید. میتوانید این انتقال را درحالیکه هنوز در Room 2.x هستید انجام دهید.
در
build.gradle.ktsواحدتان، افزونه KSP را اعمال کنید:plugins { id("com.google.devtools.ksp") version "<ksp_version>" }مطمئن شوید که نسخه KSP با نسخه Kotlin شما سازگار باشد.
kaptیاannotationProcessorرا باkspبرای وابستگی کامپایلر Room جایگزین کنید:dependencies { implementation(libs.androidx.room.runtime) ksp(libs.androidx.room.compiler) }
پذیرفتن روالهای مشترک
Room 3.0 برای عملیات ناهمگام به کوروتین نیاز دارد.
- DAO خود را بهروز کنید: همه عملکردهای DAO باید عملکرد
suspendباشند، مگراینکه نوع واکنشی قابلمشاهدهای را برگردانند، مانندFlowیا انواع RxJava.
// 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()
از میاناهای برنامهسازی کاربردی درایور استفاده کنید و از Support SQLite استفاده نکنید
Room 3.0 کاملاً توسط SQLiteDriver پشتیبانی میشود و دیگر از
SupportSQLiteDatabase در میاناهای برنامهسازی کاربردی اصلی خود پشتیبانی نمیکند.
اگر setDriver را برای تنظیم SQLiteDriver در سازنده پایگاه دادهتان فراخوانی نکنید،
Room 2.8 در حالت سازگاری عمل میکند که در آن هم Support SQLite و هم Driver
APIs کار میکنند. این حالت سازگاری به شما امکان میدهد پایگاه کدتان را قبلاز فعال کردن درایور بهصورت افزایشی تبدیل کنید.
- انتقالهای تبدیل: زیرکلاسهای
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، ازRoomRawQueryبهجایSupportSQLiteQueryاستفاده کنید:
// 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)
}
)
- تبدیل کردن میاناهای برنامهسازی کاربردی تراکنش: بلوکهای
withTransactionوrunInTransactionمختص Android را با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: پساز اینکه همه موارد استفاده از Room API را به میاناهای برنامهسازی کاربردی درایور منتقل کردید، درایوری مثل
BundledSQLiteDriverیاAndroidSQLiteDriverرا با فراخوانیsetDriverدر سازندهRoomDatabaseپیکربندی کنید:
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
val db = Room.databaseBuilder<AppDatabase>(context, "db")
.setDriver(BundledSQLiteDriver())
.build()
اتخاذ ردگیری ابطال مبتنی بر جریان
Room 2.8 InvalidationTracker.createFlow API را معرفی میکند. از این میانای برنامهسازی کاربردی استفاده کنید
تا از پیادهسازیهای قدیمی InvalidationTracker.Observer مهاجرت کنید
درحالیکه هنوز در Room 2.x هستید. این کار پایگاه کد شما را برای Room 3.0 آماده میکند که
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 3.0
وقتی برنامهتان را در 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 androidx.room.*را باimport androidx.room3.*جایگزین کنید.
بهروزرسانی میاناهای برنامهسازی کاربردی تبدیلکننده نوع
Room 3.0 نام میاناهای برنامهسازی کاربردی تبدیلکننده نوع را تغییر میدهد تا کاربرد آنها را برای تبدیل مقادیر ستون شفافسازی کند و از سردرگمی با تبدیلکنندههای نوع بازگشتی 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()
بهروزرسانی فراخوانیهای برگشتی برای تعلیق عملکردها
در Room 3.0، بازخوانیها و انتقالهای پایگاه داده از 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
در Room 3.0، انواع بازگشت واکنشی، مانند 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): ثبتLiveDataDaoReturnTypeConverterازandroidx.room3:room3-livedataمصنوع.
تأیید حذف InvalidationTracker Observer
Room 3.0 بهطور کامل InvalidationTracker.Observer و روشهای ثبتنام مرتبط، مانند addObserver و removeObserver را حذف میکند.
اگر قبلاً در فاز ۱ به جریانهای همروال منتقل نشدهاید، باید همه موارد استفاده از Observer را به createFlow منتقل کنید:
val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
userDao.getAllUsers()
}