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 协程 进行 异步处理,使数据库操作更加流畅高效。

相关推荐
代码搬运媛7 小时前
Jest 测试框架详解与实现指南
前端
counterxing8 小时前
我把 Codex 里的 Skills 做成了一个 MCP,还支持分享
前端·agent·ai编程
wangqiaowq8 小时前
windows下nginx的安装
linux·服务器·前端
之歆8 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
发现一只大呆瓜8 小时前
Vite凭什么这么快?3分钟带你彻底搞懂 Vite 热更新的幕后黑手
前端·面试·vite
Maimai108088 小时前
React如何用 @microsoft/fetch-event-source 落地 SSE:比原生 EventSource 更灵活的实时推送方案
前端·javascript·react.js·microsoft·前端框架·reactjs·webassembly
kyriewen10 小时前
产品经理把PRD写成“天书”,我用AI半小时重写了一遍,他当场愣住
前端·ai编程·cursor
humcomm11 小时前
元框架的工作原理详解
前端·前端框架
canonical_entropy11 小时前
Attractor Before Harness: AI 大规模开发的方法论
前端·aigc·ai编程
zhangxingchao11 小时前
多 Agent 架构到底怎么选?从 Claude Agent Teams、Cognition/Devin 到工程落地原则
前端·人工智能·后端