Android Room用法详解

Room 是 Android 官方推荐的数据库框架,它是 SQLite 的抽象封装,提供了更便捷的数据库操作方式,支持 Kotlin 协程和 LiveData。以下是 Room 的基本使用方法:


1. 添加 Room 依赖

build.gradle.kts(模块级)中添加 Room 相关依赖:

kotlin 复制代码
dependencies {
    val room_version = "2.6.1" // 确保使用最新版本
​
    implementation("androidx.room:room-runtime:$room_version")
    kapt("androidx.room:room-compiler:$room_version") // 用于注解处理器
​
    implementation("androidx.room:room-ktx:$room_version") // 支持 Kotlin 协程
}

如果项目使用 Kotlin Symbol Processing (KSP) 代替 kapt:

bash 复制代码
ksp("androidx.room:room-compiler:$room_version")

2. 创建数据库实体(Entity)

使用 @Entity 注解定义数据库表:

kotlin 复制代码
import androidx.room.Entity
import androidx.room.PrimaryKey
​
@Entity(tableName = "diary_entries") // 指定表名
data class DiaryEntry(
    @PrimaryKey(autoGenerate = true) val id: Int = 0, // 主键,自动生成
    val title: String,
    val content: String,
    val date: Long, // 以时间戳形式存储日期
    val weather: String? = null
)

3. 创建 DAO(数据访问对象)

DAO 负责数据库的 CRUD 操作:

less 复制代码
import androidx.room.*
​
@Dao
interface DiaryDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertDiary(entry: DiaryEntry)
​
    @Update
    suspend fun updateDiary(entry: DiaryEntry)
​
    @Delete
    suspend fun deleteDiary(entry: DiaryEntry)
​
    @Query("SELECT * FROM diary_entries ORDER BY date DESC")
    fun getAllDiaries(): List<DiaryEntry> // 直接返回列表(不推荐,建议使用 Flow)
​
    @Query("SELECT * FROM diary_entries WHERE id = :id")
    suspend fun getDiaryById(id: Int): DiaryEntry?
​
    @Query("SELECT * FROM diary_entries WHERE title LIKE '%' || :query || '%'")
    fun searchDiaries(query: String): List<DiaryEntry>
}

如果需要监听数据变化,可以用 Flow

kotlin 复制代码
@Query("SELECT * FROM diary_entries ORDER BY date DESC")
fun getAllDiariesFlow(): Flow<List<DiaryEntry>> // 使用 Flow 以支持实时监听

4. 创建数据库(Database)

使用 @Database 注解创建 Room 数据库:

kotlin 复制代码
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
​
@Database(entities = [DiaryEntry::class], version = 1, exportSchema = false)
abstract class DiaryDatabase : RoomDatabase() {
    abstract fun diaryDao(): DiaryDao
​
    companion object {
        @Volatile
        private var INSTANCE: DiaryDatabase? = null
​
        fun getDatabase(context: Context): DiaryDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    DiaryDatabase::class.java,
                    "diary_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

说明

  • @Volatile 确保多个线程能正确访问 INSTANCE
  • synchronized(this) 确保数据库实例的单例模式。

5. 在 ViewModel 中使用

ViewModel 里封装数据库操作:

kotlin 复制代码
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.Flow
​
class DiaryViewModel(private val diaryDao: DiaryDao) : ViewModel() {
    val allDiaries: Flow<List<DiaryEntry>> = diaryDao.getAllDiariesFlow()
​
    suspend fun addDiary(entry: DiaryEntry) {
        diaryDao.insertDiary(entry)
    }
​
    suspend fun deleteDiary(entry: DiaryEntry) {
        diaryDao.deleteDiary(entry)
    }
}

viewmodel 目录下新建 DiaryViewModelFactory.kt 文件,并写入以下代码:

kotlin 复制代码
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.uibestpractice.data.DiaryDao // 替换为你的包名
​
class DiaryViewModelFactory(private val diaryDao: DiaryDao) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(DiaryViewModel::class.java)) {
            return DiaryViewModel(diaryDao) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }

6. 在 Activity/Fragment 中使用

ActivityFragment 里使用 ViewModel:

kotlin 复制代码
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
​
class MainActivity : AppCompatActivity() {
    private val diaryViewModel: DiaryViewModel by viewModels {
        DiaryViewModelFactory(DiaryDatabase.getDatabase(this).diaryDao())
    }
​
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
​
        // 监听数据库变化
        lifecycleScope.launch {
            diaryViewModel.allDiaries.collect { diaryList ->
                // 更新 UI
            }
        }
    }
​
    private fun addDiaryEntry() {
        lifecycleScope.launch {
            val newEntry = DiaryEntry(title = "新日记", content = "今天很开心!", date = System.currentTimeMillis())
            diaryViewModel.addDiary(newEntry)
        }
    }
}

7. 线程调度(协程)

Room 允许在 suspend 函数中调用数据库操作,Kotlin 协程会自动切换到 IO 线程:

kotlin 复制代码
suspend fun insertDiary(entry: DiaryEntry) {
    diaryDao.insertDiary(entry) // Room 在 IO 线程执行
}

对于 不支持协程的函数 (如 getAllDiaries()),应使用 withContext(Dispatchers.IO)

kotlin 复制代码
fun getAllDiariesBlocking(): List<DiaryEntry> {
    return runBlocking { withContext(Dispatchers.IO) { diaryDao.getAllDiaries() } }
}

总结

Room 提供了 简单、安全、高效 的数据库管理:

  1. Entity (表) → @Entity
  2. DAO (数据操作) → @Dao
  3. Database (数据库实例) → @Database
  4. ViewModel(封装业务逻辑)
  5. Activity/Fragment(UI 层使用数据库)

你可以结合 Flow 进行 实时监听 ,结合 Kotlin 协程 进行 异步处理,使数据库操作更加流畅高效。

相关推荐
我是小路路呀1 分钟前
vue开始时间小于结束时间,时间格式:年月日时分
前端·javascript·vue.js
虾球xz3 分钟前
游戏引擎学习第201天
前端·学习·游戏引擎
我自纵横202314 分钟前
JavaScript 中常见的鼠标事件及应用
前端·javascript·css·html·计算机外设·ecmascript
li_Michael_li15 分钟前
Vue 3 模板引用(Template Refs)详解与实战示例
前端·javascript·vue.js
excel18 分钟前
webpack 核心编译器 十五 节
前端
excel23 分钟前
webpack 核心编译器 十六 节
前端
雪落满地香2 小时前
css:圆角边框渐变色
前端·css
风无雨4 小时前
react antd 项目报错Warning: Each child in a list should have a unique “key“prop
前端·react.js·前端框架
人无远虑必有近忧!4 小时前
video标签播放mp4格式视频只有声音没有图像的问题
前端·video
安分小尧9 小时前
React 文件上传新玩法:Aliyun OSS 加持的智能上传组件
前端·react.js·前端框架