Room 3.0 是一项主要版本更新,可将库转换为 Kotlin 优先。它支持 Kotlin Multiplatform (KMP),需要 Kotlin 符号处理 (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。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 及更高版本
更新 build 配置以使用当前的 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 符号处理 (KSP)。您可以在仍使用 Room 2.x 的同时进行此转换。
在模块的
build.gradle.kts中,应用 KSP 插件:plugins { id("com.google.devtools.ksp") version "<ksp_version>" }确保 KSP 版本与您的 Kotlin 版本兼容。
对于 Room 编译器依赖项,将
kapt或annotationProcessor替换为ksp: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 会在兼容性模式下运行,其中 Support 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块替换为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 从 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。在仍使用 Room 2.x 的同时,使用此 API 迁移离开旧版 InvalidationTracker.Observer 实现。这样可以为 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 涉及更新依赖项、软件包导入和数据库回调。
更新依赖项和软件包导入
- 在 build 配置中,将
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,以明确其用于转换列值的用法,并避免与 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>
}
- Paging (
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 Observer 移除情况
Room 3.0 完全移除了 InvalidationTracker.Observer 和相关注册方法,例如 addObserver 和 removeObserver。
如果您尚未在
第 1 阶段转换为协程流,则必须将所有 Observer 用法迁移到
createFlow:
val userFlow = db.invalidationTracker.createFlow("User").map { _ ->
userDao.getAllUsers()
}