Android Jetpack 之使用 Room 操作数据库

Room 是 Android Jetpack 中用来处理数据库的框架,它可以用来替代原有的 SQLiteOpenHelper,简化数据库操作。

Android Room with a View 是一个 Google Codelab 用来展示 Jetpack Room 用法的 app。它可以输入一个单词并自动刷新显示数据库中的所有单词。通过 Android Room with a View 这个项目可以熟悉 Android Jetpack 的 LiveData、ViewModel、Room 的用法。

Room 需要先新建一个 abstract 的 RoomDatabase 类,它继承自 RoomDatabase。

abstract class WordRoomDatabase : RoomDatabase() {

使用 @Database 注解表明使用 RoomDatabase 构造数据库。

@Database 注解有 2 个 方法:

  • entities 表示数据库中有哪些表。通常用一个数据类表示表结构,比如 Word::class。
  • version 表示当前数据库的版本号。数据库升级时会用到版本号。
@Database(entities = [Word::class], version = 1)

WordRoomDatabase 类有一个抽象方法,用来返回 Dao 类,比如 WordDao。WordDao 定义了数据的增删改查接口。

abstract class WordRoomDatabase : RoomDatabase() {
    abstract fun wordDao(): WordDao

getDatabase 方法使用单例模式构造 WordRoomDatabase 的实例。

abstract class WordRoomDatabase : RoomDatabase() {
        fun getDatabase(context: Context, scope: CoroutineScope): WordRoomDatabase {
            return INSTANCE ?: synchronized(this) {
                var instance = Room.databaseBuilder(
                        context.applicationContext,
                        WordRoomDatabase::class.java,
                        "word_database"
                        // when migrate database, wipes and rebuilds database
                        .fallbackToDestructiveMigration()
                        .addCallback(WordDatabaseCallback(scope))
                        .build()
                INSTANCE = instance
                instance

getDatabase 使用 Room.databaseBuilder 构造 database。databaseBuilder 可以传入一个 Callback,它可以在数据库的生命周期执行回调,比如 database 的 onCreate 执行数据库的初始化操作,插入几条数据。

        class WordDatabaseCallback(private val scope: CoroutineScope) : RoomDatabase.Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                // init database content
                INSTANCE?.let { database ->
                    scope.launch(Dispatchers.IO) {
                        populateDatabase(database.wordDao())

完整的 WordRoomDatabase 代码如下:

@Database(entities = [Word::class], version = 1)
abstract class WordRoomDatabase : RoomDatabase() {
    abstract fun wordDao(): WordDao
    companion object {
        @Volatile
        private var INSTANCE: WordRoomDatabase? = null
        fun getDatabase(context: Context, scope: CoroutineScope): WordRoomDatabase {
            return INSTANCE ?: synchronized(this) {
                var instance = Room.databaseBuilder(
                        context.applicationContext,
                        WordRoomDatabase::class.java,
                        "word_database"
                        // when migrate database, wipes and rebuilds database
                        .fallbackToDestructiveMigration()
                        .addCallback(WordDatabaseCallback(scope))
                        .build()
                INSTANCE = instance
                instance
        class WordDatabaseCallback(private val scope: CoroutineScope) : RoomDatabase.Callback() {
            override fun onCreate(db: SupportSQLiteDatabase) {
                super.onCreate(db)
                // init database content
                INSTANCE?.let { database ->
                    scope.launch(Dispatchers.IO) {
                        populateDatabase(database.wordDao())
        suspend fun populateDatabase(wordDao: WordDao) {
            wordDao.deleteAll()
            var word = Word("Hello")
            wordDao.insert(word)
            word = Word("World!")
            wordDao.insert(word)

LiveData 与 Flow

LiveData 将数据转换为可以被观察的数据。当数据发生变化时,LiveData 会将变化传递给 LiveData 定义的观察者。

wordViewModel.allWords 是一个 LiveData,当 words 发生变化时通知 adapter 刷新 recyclerview。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        wordViewModel.allWords.observe(this) { words ->
            words.let {
                adapter.submitList(it)

repository.allWords 是 wordDao 定义的 Flow 流,它以 Flow 异步流的形式返回 Word 列表。

asLiveData 方法将 Flow 转换为 LiveData。

class WordViewModel(private val repository: WordRepository) : ViewModel() {
    val allWords: LiveData<List<Word>> = repository.allWords.asLiveData()
class WordRepository(private val wordDao: WordDao) {
    val allWords: Flow<List<Word>> = wordDao.getAlphabetizeWords()

lifecycle-livedata-ktx 依赖库的 FlowLiveData.kt 文件定义了 asLiveData 扩展函数。它可以将 Flow 转换为 LiveData。当数据库发生变化时,Flow 可以实时更新,从而通知 LiveData 刷新界面。

fun <T> Flow<T>.asLiveData(
    context: CoroutineContext = EmptyCoroutineContext,
    timeoutInMs: Long = DEFAULT_TIMEOUT
): LiveData<T> = liveData(context, timeoutInMs) {
    collect {
        emit(it)

实际上 Flow 的构造过程定义在 room-ktx 依赖库的 CoroutinesRoom 类的 createFlow,它给数据库加上了观察者(observer)。

class CoroutinesRoom private constructor() {
        @JvmStatic
        fun <R> createFlow(
            db: RoomDatabase,
            inTransaction: Boolean,
            tableNames: Array<String>,
            callable: Callable<R>
        ): Flow<@JvmSuppressWildcards R> = flow {

WordDao 数据访问接口在查询时返回 Flow。

interface WordDao { // Flow notify @Query("SELECT * FROM word_table ORDER BY word ASC") fun getAlphabetizeWords(): Flow<List<Word>> * ignore 如果有冲突就不插入 @Insert(onConflict = OnConflictStrategy.IGNORE) suspend fun insert(word: Word) @Query("DELETE FROM word_table") suspend fun deleteAll()

最后在 WordViewModel 保存 LiveData。外部 Activity 通过 WordViewModel 操作数据。

class WordViewModel(private val repository: WordRepository) : ViewModel() {
    val allWords: LiveData<List<Word>> = repository.allWords.asLiveData()

Codelab : Android Room with A View - Kotlin

googlecodelabs/android-room-with-a-view

Kotlin 数据流

Android Jetpack 之使用 Room 操作数据库Room 是 Android Jetpack 中用来处理数据库的框架,它可以用来替代原有的 SQLiteOpenHelper,简化数据库操作。Android Room with a View 是一个 Google Codelab 用来展示 Jetpack Room 用法的 app。它可以输入一个单词并自动刷新显示数据库中的所有单词。通过 Android Room with a View 这个项目可以熟悉 Android Jetpack 的 Li Android Jetpack架构组件-Room基本使用 Android Jetpack架构组件-Room数据库查询艺术 Android Jetpack架构组件-Room升级 在Android使用任何一种数据库框架,少不了应用的迭代和数据库的升级,那么Room的该如何正确的升级? 一、Room数据库升级 第一步:增加version数据,及版本号增加 @Database(entities = [Cheese::class, User::class], version = 2, exportSchema = true) abstract class CheeseDb :
使用 Room 库存储应用数据时,通过定义数据访问对象(DAOs)与存储的数据进行交互。每一个 DAO 包含用来访问应用数据库的抽象方法,在编译时, Room 会自动生成并实现在 DAO 中定义的访问方法 另外,本文本还介绍了 DAO 异步查询的相关内容,为了防止数据查询操作阻断 UI,造成 UI 卡顿,Room 不允许在 UI 主线程中访问数据库。这就意味着开发者必须将 DAO 中的查询定义成异步的。Room 库包含与多阿哥不同的框架进行集成,提供异步查询支持。
一.Room简介 Room是Google推出的数据库框架,是一个 ORM (Object Relational Mapping)对象关系映射数据库、其底层还是对SQLite的封装。 使用ORM可以让开发者更加关注业务逻辑,而不是SQL 语句。在JavaWeb领域也有类似的ORM 数据库框架Hibernate、MyBatis等等。 1.Android平台数据库框架 在 Android 中常见的数据库框架: Greendao Realm DBFlow LitePal Jetpack-Room
相关文章: JetpackRoom超详细使用踩坑指南! Jetpack:Room+kotlin协程? 事务问题分析,withTransaction API 详解. Room在搭建的时候出现几个小问题,记录一下。基本都是配置问题: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (no such table: simple_student)。 编译的时候报错,找不到表。 需要在声明 def room_version = "2.3.0" implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" // 可选 - RxJava2 suppor
安卓jetpackroom数据库框架是基于Sqlite3的数据库,但是有别于sqlite,因此使用查看sqlite的数据库可视化软件看不到room数据库的值(但是可以打开), 使用Androidstudio自带的databaseinspector,高版本的AS需要在APP inspection里面打开,另外应用必须是debug版本
Room 是 Google 官方推出的数据库 **ORM 框架**。ORM:即 Object Relational Mapping,即对象关系映射,也就是将关系型数据库映射为面向对象的语言。使用 ORM 框架,我们就可以用面向对象的思想操作关系型数据库,不再需要编写 SQL 语句。 Room 是在 **SQLite** 的基础上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够更简便的访问数据库