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

相关推荐
会豪13 分钟前
Electron-Vite (一)快速构建桌面应用
前端
中微子16 分钟前
React 执行阶段与渲染机制详解(基于 React 18+ 官方文档)
前端
唐某人丶17 分钟前
教你如何用 JS 实现 Agent 系统(2)—— 开发 ReAct 版本的“深度搜索”
前端·人工智能·aigc
中微子18 分钟前
深入剖析 useState产生的 setState的完整执行流程
前端
遂心_43 分钟前
JavaScript 函数参数传递机制:一道经典面试题解析
前端·javascript
小徐_23331 小时前
uni-app vue3 也能使用 Echarts?Wot Starter 是这样做的!
前端·uni-app·echarts
RoyLin1 小时前
TypeScript设计模式:适配器模式
前端·后端·node.js
遂心_1 小时前
深入理解 React Hook:useEffect 完全指南
前端·javascript·react.js
Moonbit1 小时前
MoonBit 正式加入 WebAssembly Component Model 官方文档 !
前端·后端·编程语言
龙在天1 小时前
ts中的函数重载
前端