一、Room + ViewModel + LiveData 框架使用核心要点
1、Room 框架优化分析
在上一篇博客 【Jetpack】使用 Room 框架访问 Android 平台 SQLite 数据库 ( 导入依赖 | 定义 Entity 实体类 | 定义 Dao 数据库访问对象接口 | 定义数据库实例类 ) 中 , 实现了 使用 Room 框架访问 Android 中的 SQLite 数据库的操作 , 每当数据库中的数据发生变化时 , 就需要开启线程 , 重新获取数据库中的数据 ;
为了优化上述问题 , 可以引入 LiveData 和 ViewModel ,
- ViewModel 是 视图 View 与 数据模型 Model 之间 数据交互的 桥梁 ;
- LiveData 是基于 ViewModel 的 , 是 对 ViewModel 数据维护的一个补充 ;
在 ViewModel 中使用了 LiveData 后 ,
先调用 LiveData#observe 函数 为 LiveData 设置 androidx.lifecycle.Observer 监听器 ,
如果 该监听器 监听到了 LiveData 数据变化 ,
直接 回调 androidx.lifecycle.Observer 监听器 的 androidx.lifecycle.Observer#onChanged 函数 ,
最终在上述回调函数中执行 查询数据库 和 更新视图 操作 ;
2、Google 官方建议的 Room + ViewModel + LiveData 架构
下图是 Google 官方 提出的 Room + ViewModel + LiveData 架构设计 建议 :
在这里插入图片描述
下面分析上述 架构图 中的 架构分层 ;
Model 数据模型层 :
- 本地数据访问 : 使用 Room 框架 访问本地的 SQLite 数据库 ;
- 远程数据访问 : 使用 Retrofit 框架 访问 远程数据源 ( Remote Data Source ) ;
Repository 层 : 该层负责 封装 Model 数据模型层 , 用于与 ViewModel 层进行交互 ;
ViewModel 视图模型层 : 该层 不与 Room 和 Retrofit 直接交互 , 而是与 Repository 层 进行交互 ; 在 ViewModel 层引入 LiveData 监听数据变化 , 如果数据发生变化则在 LiveData 设置的 androidx.lifecycle.Observer 监听器回调中 更新 View 视图 ;
View 视图层 : Activity / Fragment 负责视图显示的 系统组件 , 负责维护 Android 视图组件 , 显示的数据由 ViewModel 提供 ;
3、Room 与 LiveData 结合使用要点
对于 Room 框架使用来说 ,
- Room 与 LiveData 结合使用 ,
- Room 单独使用 ,
唯一的区别是 Room 框架中的 Dao 数据访问接口对象 中的 查询方法 , 其返回值类型改为 LiveData 类型 , LiveData 的泛型为 原来的查询方法的返回值类型 ;
Dao 查询方法的返回值由 List<Student> 变为 LiveData<List<Student>> ;
Room 框架中 , Entity 实体类 , Database 数据库实体类 , 定义方式保持不变 ,
- Entity 实体类 使用 @Entity 注解修饰 , 并使用 @PrimaryKey 注解修饰主键 , 使用 @ColumnInfo 注解 修饰普通字段 , 使用 @Ignore 注解 修饰不需要的字段或方法 ;
- Database 数据库实体类 使用 @Database 注解修饰该类 , 其中定义 获取 Dao 数据库访问对象的抽象方法 , 以及 将该抽象类设置成 单例类 , 在单例对象初始化时创建数据库 ;
在 Room 框架中的 Dao 数据库访问对象接口 的定义方式需要作出改变 , 涉及到数据库查询的 接口方法时 , 其返回值需要 返回 LiveData 类型 , 泛型设置为 List<Student> 类型 ;
/**
* 查询数据库表
*/
@Query("select * from student")
fun query(): LiveData<List<Student>>
/**
* 根据传入的 id 查询数据库表
* 在注解中使用 :id 调用参数中的 id: Int
*/
@Query("select * from student where id = :id")
fun query(id: Int): LiveData<List<Student>>
复制
原来的方法如下 , 其查询接口的返回值是 List<Student> ;
/**
* 查询数据库表
*/
@Query("select * from student")
fun query(): List<Student>
/**
* 根据传入的 id 查询数据库表
* 在注解中使用 :id 调用参数中的 id: Int
*/
@Query("select * from student where id = :id")
fun query(id: Int): List<Student>
复制
Room 框架的用法 , 参考 【Jetpack】使用 Room 框架访问 Android 平台 SQLite 数据库 ( 导入依赖 | 定义 Entity 实体类 | 定义 Dao 数据库访问对象接口 | 定义数据库实例类 ) 博客 ;
4、Repository 层核心要点
Repository 层负责 封装 Model 数据模型层 , 用于与 ViewModel 层进行交互 ;
因此在 Repository 中 , 需要 持有 Dao 数据访问接口对象 ;
lateinit var dao: StudentDao
复制
而 Dao 又是通过 Database 得到的 ,
因此在 该 Repository 中需要先获取 Database 数据库实例类对象 , 然后通过 Database 获取 Dao 数据访问接口 ;
constructor(context: Context) {
var database = StudentDatabase.inst(context)
this.dao = database.studentDao()
}
复制
此外 , 还需要 在 Repository 层中 , 维护数据库的 增