Actor 是一个用 @Entity 注解的 data class,它会生成一个名字是 actors 的表,注意到有一个字段是 @Date? ,但是 SQLite 本身不支持这种复杂类型(complex type),所以我们还需要写一个可以转换成基础类型的转换器:
class Converters {
@TypeConverter
fun timestampToDate(value: Long?) = value?.let { Date(it) }
@TypeConverter
fun dateToTimestamp(date: Date?) = date?.time
}
转换器通过 @TypeConverters 可作用于 class、field、method、parameter,分别代表不同的作用域。比如作用在 @Database 类的上,那么它的作用域就是 db 中出现的所有 @Dao 和 @Entity。
@Database(entities = [Actor::class], version = 1, exportSchema = false)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun actorDao(): ActorDao
}
代码出现的 ActorDao 定义了 CRUD 操作。用 @Dao 来注解,它既可以是一个接口,也可以是抽象类,用法如下:
@Dao
interface ActorDao {
@Query(“SELECT * FROM actors WHERE id = :actorId”)
fun getActor(actorId: String): LiveData
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(actors: List)
}
@Query 中的 SQL 语句可以直接引用方法参数,而且它的返回值可以是 LiveData 类型,也支持 Flowable 类型,也就是说,Room 原生支持响应式,这是对数据驱动最有利的支持,也是 Room 区别于其他 ORM 框架的显著特征。
至此,我们可以确定,无论数据来自 Remote 还是来自本地 DB,架构蓝图中的 Repository 对 ViewModel 提供的数据可以永远是 LiveData 类型,接下来我们看一下 ViewModel 的妙用。
ViewModel
ViewModel 是一个多面手,因为它的生命周期比较长,可以跨越因为配置变动(configuration changed,比如屏幕翻转)引起的 Activity 重建,因此 ViewModel 不能持有对 Activity / Fragment 的引用。
如果 ViewModel 中要用到 context 怎么办呢?没关系,框架提供了一个 ViewModel 的子类 AndroidViewModel ,它在构造时需要传入 Application 实例。
既然 ViewModel 与 UI Controller 无关,当然可以用作 MVP 的 Presenter 层提供 LiveData 给 View 层,因为 LiveData 绑定了 Lifecycle,所以不存在内存泄露的问题。除此之外&#