Room 3.0 是主要版本更新,可將程式庫轉換為以 Kotlin 為主。支援 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 程式碼產生作業。請使用 KSP,而非 KAPT 或 Java 註解處理工具。Room 3.0 仍支援將 Java 來源做為輸入內容。
- 優先使用協同程式:DAO 函式必須是
suspend函式,可觀測型別除外。CoroutineContext會取代執行器。 - 不支援 SupportSQLite:
SQLiteDriverAPI 會返回 Room。從核心 API 中移除會議室「SupportSQLiteDatabase」。 - API 變更:遷移作業和資料庫回呼會使用
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 使用的許多驅動程式 API。
更新至 Room 2.8 以上版本
更新建構設定,使用目前的 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:除非傳回可觀察的反應式型別 (例如
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>
}
- 如果您使用自訂
Executor設定RoomDatabase來執行資料庫作業,請在建構工具上使用setQueryCoroutineContext遷移至CoroutineContext:
Room.databaseBuilder<AppDatabase>(context, "db")
.setQueryCoroutineContext(Dispatchers.IO)
.build()
採用驅動程式 API,避免使用 Support SQLite
Room 3.0 完全由 SQLiteDriver 支援,不再支援核心 API 中的 SupportSQLiteDatabase。
如果您未呼叫 setDriver 在資料庫建構工具上設定 SQLiteDriver,Room 2.8 會以相容模式運作,支援 SQLite 和驅動程式 API。這個相容模式可讓您在啟用驅動程式前,逐步轉換程式碼集。
- 轉換遷移作業:將
Migration和AutoMigrationSpec子類別遷移為使用SQLiteConnection,而非SupportSQLiteDatabase。
// 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) {
// ...
}
}
- 轉換
@RawQueryDAO 函式:對於以@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)
}
)
- 轉換交易 API:將僅限 Android 的
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。
- 避免直接使用
SupportSQLiteDatabase:如果您有大量仍需使用SupportSQLiteDatabase的舊版程式碼,且目前無法遷移,請使用androidx.room:room-sqlite-wrapper相容性構件:
dependencies {
implementation("androidx.room:room-sqlite-wrapper:$roomVersion")
}
然後,使用 getSupportWrapper 從 Room 資料庫例項取得 SupportSQLiteDatabase:
import androidx.room.support.getSupportWrapper
val legacyDb: SupportSQLiteDatabase = roomDatabase.getSupportWrapper()
- 設定 SQLite 驅動程式:將所有 Room API 用法遷移至驅動程式 API 後,請在
RoomDatabase建構工具中呼叫setDriver,設定BundledSQLiteDriver或AndroidSQLiteDriver等驅動程式:
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
val db = Room.databaseBuilder<AppDatabase>(context, "db")
.setDriver(BundledSQLiteDriver())
.build()
採用以流程為基礎的失效原因追蹤
Room 2.8 推出 InvalidationTracker.createFlow API。使用這個 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.*。
更新型別轉換器 API
Room 3.0 會重新命名型別轉換器 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()
將回呼更新為暫停函式
在 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) 需要使用 @DaoReturnTypeConverters 註冊 DAO 傳回類型轉換器。
import androidx.room3.paging.PagingSourceDaoReturnTypeConverter
@Dao
@DaoReturnTypeConverters(PagingSourceDaoReturnTypeConverter::class)
interface UserDao {
@Query("SELECT * FROM User")
fun getAllPaginated(): PagingSource<Int, User>
}
- 分頁 (
PagingSource):從androidx.room3:room3-paging構件註冊PagingSourceDaoReturnTypeConverter。 - RxJava (
Observable、Flowable、Single、Maybe、Completable): 從androidx.room3:room3-rxjava3構件註冊RxDaoReturnTypeConverters。 - Guava (
ListenableFuture):從androidx.room3:room3-guava構件註冊GuavaDaoReturnTypeConverter。 - LiveData (
LiveData):從androidx.room3:room3-livedata構件註冊LiveDataDaoReturnTypeConverter。
確認移除 InvalidationTracker 觀察器
Room 3.0 完全移除了 InvalidationTracker.Observer 和相關的註冊方法,例如 addObserver 和 removeObserver。
如果您尚未在第 1 階段轉換為協同程式流程,請務必將所有 Observer 用法遷移至 createFlow:
val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
userDao.getAllUsers()
}