在 Android 应用开发中,数据持久化是实现用户数据保存、应用状态保存等功能的重要手段。Room 是 Google 推出的一个基于 SQLite 的持久化库,提供了更简洁、安全和强大的数据库操作接口。Room 抽象了 SQLite 数据库的使用,简化了数据库操作,并提供了编译时 SQL 语句检查等功能。本章节将介绍 Room 数据库的基本概念、架构、常用注解以及在 Android 项目中的应用,帮助学员掌握 Room 数据库的使用。
15.1 Room 简介
-
Room 的历史与发展:
- Room 是 Google 在 2017 年推出的持久化库,旨在简化 Android 应用中的 SQLite 数据库操作。
- Room 提供了更简洁的 API,编译时 SQL 语句检查,以及与 LiveData 和 Flow 的无缝集成。
-
Room 的优势:
- 简洁易用: 相比直接使用 SQLite,Room 提供了更简洁的 API,简化了数据库操作。
- 编译时检查: Room 在编译时会检查 SQL 语句的正确性,避免运行时错误。
- 与 LiveData 和 Flow 集成: Room 支持与 LiveData 和 Flow 集成,可以方便地观察数据库数据的变化。
- 支持注解: Room 使用注解来定义实体、DAO 和数据库,代码更简洁易读。
- 线程安全: Room 默认在后台线程中执行数据库操作,避免阻塞主线程。
15.2 Room 架构
Room 主要由三个组件组成:
-
Entity(实体):
- 实体类表示数据库中的表。
- 使用
@Entity
注解定义实体类,并使用@PrimaryKey
,@ColumnInfo
等注解定义表结构和字段。
@Entity(tableName = "users") data class User( @PrimaryKey(autoGenerate = true) val id: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
-
DAO(数据访问对象):
- DAO 类用于定义数据库操作,例如查询、插入、更新、删除等。
- 使用
@Dao
注解定义 DAO 接口,并使用@Query
,@Insert
,@Update
,@Delete
等注解定义数据库操作方法。
@Dao interface UserDao { @Query("SELECT * FROM users") fun getAllUsers(): LiveData<List<User>> @Query("SELECT * FROM users WHERE id = :id") fun getUserById(id: Int): User @Insert suspend fun insertUser(user: User) @Update suspend fun updateUser(user: User) @Delete suspend fun deleteUser(user: User) }
-
Database(数据库):
- Database 类是 Room 数据库的入口,用于获取 DAO 实例。
- 使用
@Database
注解定义 Database 类,并指定实体类和版本号。
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao companion object { @Volatile private var INSTANCE: AppDatabase? = null fun getDatabase(context: Context): AppDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, AppDatabase::class.java, "app_database" ).build() INSTANCE = instance instance } } } }
15.3 Room 常用注解
-
@Entity:
- 定义实体类,表示数据库中的表。
- 可以使用
tableName
属性指定表名。 - 可以使用
primaryKeys
,foreignKeys
,indices
等属性定义表的主键、外键和索引。
@Entity(tableName = "users") data class User( @PrimaryKey(autoGenerate = true) val id: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
-
@Dao:
- 定义 DAO 接口,用于定义数据库操作。
- 可以使用
@Query
,@Insert
,@Update
,@Delete
等注解定义数据库操作方法。
@Dao interface UserDao { @Query("SELECT * FROM users") fun getAllUsers(): LiveData<List<User>> @Insert suspend fun insertUser(user: User) @Update suspend fun updateUser(user: User) @Delete suspend fun deleteUser(user: User) }
-
@Database:
- 定义 Database 类,表示 Room 数据库。
- 需要指定实体类和版本号。
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
-
@ColumnInfo:
- 定义实体类字段对应的数据库列。
- 可以使用
name
属性指定列名。
@ColumnInfo(name = "first_name") val firstName: String?
-
@PrimaryKey:
- 定义实体类的主键。
- 可以使用
autoGenerate
属性指定主键是否自动生成。
@PrimaryKey(autoGenerate = true) val id: Int
-
@Ignore:
- 忽略实体类中的字段,不将其映射到数据库表中。
@Ignore val tempData: String?
15.4 Room 常用操作
-
插入数据:
@Insert suspend fun insertUser(user: User)
-
查询数据:
@Query("SELECT * FROM users") fun getAllUsers(): LiveData<List<User>> @Query("SELECT * FROM users WHERE id = :id") fun getUserById(id: Int): User
-
更新数据:
@Update suspend fun updateUser(user: User)
-
删除数据:
@Delete suspend fun deleteUser(user: User)
-
事务操作:
@Transaction suspend fun insertOrUpdateUser(user: User) { val existingUser = getUserById(user.id) if (existingUser != null) { updateUser(user) } else { insertUser(user) } }
15.5 Room 与 LiveData 和 Flow
Room 支持与 LiveData 和 Flow 集成,可以方便地观察数据库数据的变化。
-
与 LiveData 集成:
@Query("SELECT * FROM users") fun getAllUsers(): LiveData<List<User>>
class MyActivity : AppCompatActivity() { private lateinit var viewModel: MyViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewModel = ViewModelProvider(this).get(MyViewModel::class.java) viewModel.users.observe(this) { users -> // 更新 UI } viewModel.loadUsers() } }
-
与 Flow 集成:
@Query("SELECT * FROM users") fun getAllUsers(): Flow<List<User>>
@Composable fun MyComposable(viewModel: MyViewModel) { val users by viewModel.users.collectAsState() LazyColumn { items(users) { user -> Text(text = user.firstName) } } }
15.6 实战案例
-
案例一:使用 Room 实现用户列表应用
- 定义 User 实体类。
- 定义 UserDao 接口,添加查询、插入、更新、删除方法。
- 创建 AppDatabase 类,初始化 Room 数据库。
- 创建 ViewModel,使用 Room 进行数据库操作。
- 在 Activity 中观察 ViewModel 的 LiveData,更新 RecyclerView。
-
案例二:使用 Room 实现图片浏览应用
- 定义 Image 实体类。
- 定义 ImageDao 接口,添加查询、插入、更新、删除方法。
- 创建 AppDatabase 类,初始化 Room 数据库。
- 创建 ViewModel,使用 Room 进行数据库操作。
- 在 Jetpack Compose Composable 中观察 ViewModel 的 Flow,更新 UI。
15.7 课后作业
-
任务一:使用 Room 实现用户列表应用
- 定义 User 实体类。
- 定义 UserDao 接口,添加查询、插入、更新、删除方法。
- 创建 AppDatabase 类,初始化 Room 数据库。
- 创建 ViewModel,使用 Room 进行数据库操作。
- 在 Activity 中观察 ViewModel 的 LiveData,更新 RecyclerView。
-
任务二:使用 Room 实现图片浏览应用
- 定义 Image 实体类。
- 定义 ImageDao 接口,添加查询、插入、更新、删除方法.
- 创建 AppDatabase 类,初始化 Room 数据库.
- 创建 ViewModel,使用 Room 进行数据库操作.
- 在 Jetpack Compose Composable 中观察 ViewModel 的 Flow,更新 UI.
-
任务三:使用 Room 实现网络请求缓存
- 定义网络请求结果实体类.
- 定义 DAO 接口,添加插入和查询方法.
- 创建 ViewModel,使用 Room 进行数据库操作.
- 在 Activity 中使用协程进行网络请求,并将结果保存到数据库.
- 在 Activity 中观察 ViewModel 的 LiveData,更新 UI.
通过本章节的学习,学员将能够掌握 Room 数据库的基本概念、架构、常用注解以及在 Android 项目中的应用,并能够使用 Room 进行数据持久化操作,实现应用数据的存储和查询。