35人参与 • 2025-07-17 • Android
room 是一个强大的 sqlite 对象映射库,旨在提供更健壮、更简洁、更符合现代开发模式的数据库访问方式。
核心价值: 消除大量样板代码,提供编译时 sql 验证,强制结构化数据访问,并流畅集成 livedata、flow 和 rxjava 以实现响应式 ui。
room 的使用遵循一个清晰的结构化流程:
添加依赖:
// build.gradle (module) dependencies { def room_version = "2.6.1" // 使用最新稳定版本 implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" // kotlin 使用 kapt // 可选:kotlin 扩展和协程支持 implementation "androidx.room:room-ktx:$room_version" // 可选:rxjava2 支持 implementation "androidx.room:room-rxjava2:$room_version" // 可选:rxjava3 支持 implementation "androidx.room:room-rxjava3:$room_version" // 可选:测试支持 androidtestimplementation "androidx.room:room-testing:$room_version" }
定义数据实体 (entity):
@entity
注解标注一个数据类。@primarykey
定义主键(可以是 autogenerate = true
实现自增)。@columninfo(name = "column_name")
自定义列名(可选)。@index
)、唯一约束 (@index(unique = true)
) 等。@entity(tablename = "users", indices = [index(value = ["last_name", "address"], unique = true)]) data class user( @primarykey(autogenerate = true) val id: int = 0, @columninfo(name = "first_name") val firstname: string, @columninfo(name = "last_name") val lastname: string, val age: int, val address: string? // 可空类型对应数据库可为 null )
定义数据访问对象 (dao - data access object):
@dao
注解标注一个接口或抽象类。@insert
:插入一个或多个实体。返回 long
(插入行的 id)或 long[]
/list<long>
。onconflict
参数定义冲突策略(如 onconflictstrategy.replace
)。@update
:更新一个或多个实体。返回 int
(受影响的行数)。@delete
:删除一个或多个实体。返回 int
(受影响的行数)。@query("sql_statement")
:执行自定义 sql 查询。这是最强大的注解。list<entity>
、livedata<entity>
、flow<entity>
、rxjava 类型 (single
, observable
等) 或简单类型 (int
, string
等)。:paramname
在 sql 中引用方法参数。@dao interface userdao { @insert(onconflict = onconflictstrategy.ignore) suspend fun insert(user: user): long // 协程支持 @update suspend fun update(user: user): int @delete suspend fun delete(user: user): int @query("select * from users order by last_name asc") fun getallusers(): flow<list<user>> // 使用 flow 实现响应式流 @query("select * from users where id = :userid") fun getuserbyid(userid: int): livedata<user> // 使用 livedata 观察单个用户变化 @query("select * from users where age > :minage") suspend fun getusersolderthan(minage: int): list<user> // 普通挂起函数 @query("delete from users where last_name = :lastname") suspend fun deleteusersbylastname(lastname: string): int }
定义数据库类 (database):
roomdatabase
的抽象类。@database
注解标注,并指定:entities
:包含该数据库中的所有实体类数组。version
:数据库版本号(整数)。每次修改数据库模式(表结构)时必须增加此版本号。exportschema
:是否导出数据库模式信息到文件(默认为 true
,建议保留用于版本迁移)。@dao
接口/抽象类的抽象方法(无参数)。@database(entities = [user::class, product::class], version = 2, exportschema = true) abstract class appdatabase : roomdatabase() { abstract fun userdao(): userdao abstract fun productdao(): productdao companion object { @volatile private var instance: appdatabase? = null fun getinstance(context: context): appdatabase { return instance ?: synchronized(this) { val instance = room.databasebuilder( context.applicationcontext, appdatabase::class.java, "my_app_database.db" // 数据库文件名 ) .addcallback(roomcallback) // 可选:数据库创建/打开回调 .addmigrations(migration_1_2) // 版本迁移策略 (见下文) // .fallbacktodestructivemigration() // 危险:破坏性迁移(仅开发调试) // .fallbacktodestructivemigrationondowngrade() // 降级时破坏性迁移 .build() instance = instance instance } } // 可选:数据库首次创建或打开时的回调(用于预填充数据等) private val roomcallback = object : roomdatabase.callback() { override fun oncreate(db: supportsqlitedatabase) { super.oncreate(db) // 在主线程执行!小心耗时操作。通常用协程在后台预填充。 } override fun onopen(db: supportsqlitedatabase) { super.onopen(db) // 数据库每次打开时调用 } } // 定义从版本 1 到版本 2 的迁移策略 private val migration_1_2 = object : migration(1, 2) { override fun migrate(database: supportsqlitedatabase) { // 执行必要的 sql 语句来修改数据库模式 database.execsql("alter table users add column email text") } } } }
在应用中使用数据库:
appdatabase.getinstance(context)
获取数据库实例。dao
(如 db.userdao()
)。dao
的方法执行数据库操作。illegalstateexception
)。这是为了防止 ui 卡顿。必须在后台线程(如使用 kotlin 协程
、rxjava
、livedata
+ viewmodel
+ repository
模式、executorservice
)中执行耗时操作。room-ktx
提供了对 kotlin 协程的完美支持,@dao
方法可以标记为 suspend
。livedata
或 flow
的查询方法会在数据变化时自动通知观察者,非常适合驱动 ui 更新。room 会自动在后台线程执行查询并管理 livedata
/flow
的生命周期。class userviewmodel(application: application) : androidviewmodel(application) { private val db = appdatabase.getinstance(application) private val userdao = db.userdao() // 使用 flow 暴露用户列表,repository 模式更佳 val allusers: flow<list<user>> = userdao.getallusers() fun insert(user: user) { viewmodelscope.launch(dispatchers.io) { // 在 io 线程池执行 userdao.insert(user) } } fun getuser(userid: int): livedata<user> = userdao.getuserbyid(userid) }
数据库迁移 (migration - 重要!):
@database
注解中的 version
。migration
策略告诉 room 如何从旧版本升级到新版本。使用 addmigrations(...)
添加到数据库构建器中。migration
对象重写 migrate(database: supportsqlitedatabase)
方法,在其中执行必要的 alter table
, create table
, drop table
等 sql 语句。.fallbacktodestructivemigration()
或 .fallbacktodestructivemigrationondowngrade()
。生产环境慎用!room 适用于需要结构化、关系型、本地持久化存储的场景:
livedata
/flow
)。sqliteopenhelper
和 contentprovider
: 提供更现代、更简洁、更安全的抽象层。不适合的场景:
sharedpreferences
或 datastore
。firestore
(云) 或本地 nosql 方案(虽然 room 也能存 json,但查询不高效)。room 的核心是一个编译时注解处理器,它在编译阶段生成实现代码,运行时库则提供执行环境。其设计哲学是**“抽象而不隐藏”**,开发者依然写 sql,但获得了更好的安全性和便利性。
编译时处理 (annotation processing):
room-compiler
(kapt/ksp) 扫描代码中的 @entity
, @dao
, @database
, @query
等注解。@entity
生成对应的 *_table
类(包含表名、列名、创建表 sql 等元信息)。@dao
接口/抽象类生成具体的实现类 (如 userdao_impl
)。这个实现类包含:@insert
, @update
, @delete
注解方法的实现:使用 entityinsertionadapter
, entityupdateadapter
, entitydeletionadapter
等内部类处理绑定参数和执行 sql。@query
的核心: 对于每个 @query
方法:@entity
定义)。*_query
类(如 getuserbyid_query
)。这个类::paramname
) 绑定到 sqlite 语句 (bind
方法) 的逻辑。cursor
(sqlite 查询结果游标)行数据转换为 java/kotlin 对象 (entity
或简单类型) 的逻辑 (convert
/map
方法)。@database
类生成实现类 (如 appdatabase_impl
)。这个类:appdatabase
。userdao()
),返回生成的 userdao_impl
实例。createalltables
) 和迁移相关的逻辑。supportsqliteopenhelper
实例(由 room.databasebuilder
配置),这是实际打开和管理 sqlite 数据库的核心类。运行时库 (room-runtime
):
roomdatabase
, room
等核心类和构建器 (databasebuilder
, inmemorydatabasebuilder
)。*_impl
类间接使用 supportsqliteopenhelper
(内部封装了 sqliteopenhelper
或直接使用 sqlite
api)来打开、关闭和操作实际的 sqlite 数据库文件。supportsqlite*
): room 定义了一套 supportsqlitedatabase
, supportsqlitestatement
等接口。这些接口由 room-runtime
提供的 frameworksqlite*
实现类具体实现(最终调用 android framework 的 sqlitedatabase
, sqlitestatement
)。这提供了抽象层,方便测试(可以用内存实现替换)。runintransaction
),确保操作的原子性。livedata
/flow
集成: 对于返回 livedata
或 flow
的查询方法,room 在内部使用 invalidationtracker
机制。它注册一个观察者监听底层 supportsqlitedatabase
的变化通知(通过 sqlite 的 sqlite3_update_hook
或更现代的 sqlitedatabase.oncommitlistener
等)。当检测到相关表发生修改(insert/update/delete)时,它会自动触发 livedata
更新或发射新的 flow
值(在后台线程重新执行查询并传递新结果)。typeconverter
): 如果 @entity
包含 room 不直接支持的类型(如 date
, uuid
, 自定义枚举),你可以定义 @typeconverter
类,room 会在读写数据库时自动调用这些转换器进行类型映射。核心优势原理总结:
entity
和 dao
清晰地定义了数据模型和访问接口,符合良好的架构原则(如 clean architecture)。suspend
)、响应式流(livedata
, flow
)、rxjava,简化异步编程和 ui 更新。dao
接口)使得单元测试业务逻辑时更容易 mock 数据库层。room-testing
提供测试辅助工具。总结: room 通过编译时代码生成和运行时抽象封装,将原始 sqlite api 的强大功能与现代化开发所需的类型安全、简洁性、响应式支持和架构友好性完美结合,成为 android 本地结构化数据存储的首选和标准解决方案。理解其流程、场景和原理,能帮助开发者更高效、更可靠地构建数据层。
到此这篇关于android room使用方法与底层原理详解的文章就介绍到这了,更多相关android room使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论