fun getAllDistinctUntilChanged() = getAll().distinctUntilChanged()
//添加一条搜索历史
@Insert
fun insert(history: History)
//删除一条搜索历史
@Delete
fun delete(history: History)
//更新一条搜索历史
@Update
fun update(history: History)
//根据id 删除一条搜索历史
@Query(“DELETE FROM t_history WHERE id = :id”)
fun deleteByID(id: Int)
//删除所有搜索历史
@Query(“DELETE FROM t_history”)
fun deleteAll()
}
-
@Insert:增
-
@Delete:删
-
@Update:改
-
@Query:查
这里有一个点需要注意的,就是查询所有搜索历史
返回的集合我用Flow
修饰了。
只要是数据库中的任意一个数据有更新,无论是哪一行数据的更改,那就重新执行 query
操作并再次派发Flow
。
同样道理,如果一个不相关的数据更新时,Flow
也会被派发,会收到与之前相同的数据。
//按类型 查询所有搜索历史
@Query(“SELECT * FROM t_history WHERE type=:type”)
fun getAll(type: Int = 1): Flow<List>
@ExperimentalCoroutinesApi
fun getAllDistinctUntilChanged() = getAll().distinctUntilChanged()
数据库
@Database(entities = [History::class], version = 1)
abstract class HistoryDatabase : RoomDatabase() {
abstract fun historyDao(): HistoryDao
companion object {
private const val DATABASE_NAME = “history.db”
private lateinit var mPersonDatabase: HistoryDatabase
//注意:如果您的应用在单个进程中运行,在实例化 AppDatabase 对象时应遵循单例设计模式。
//每个 RoomDatabase 实例的成本相当高,而您几乎不需要在单个进程中访问多个实例
fun getInstance(context: Context): HistoryDatabase {
if (!this::mPersonDatabase.isInitialized) {
//创建的数据库的实例
mPersonDatabase = Room.databaseBuilder(
context.applicationContext,
HistoryDatabase::class.java,
DATABASE_NAME
).build()
}
return mPersonDatabase
}
}
}
-
使用
@Database
注解声明 -
entities
数组,对应此数据库中的所有表 -
version
数据库版本号
注意:
使用
=============================================================
在需要的地方获取数据库
mHistoryDao = HistoryDatabase.getInstance(this).historyDao()
获取搜索历史
private fun getSearchHistory() {
MainScope().launch(Dispatchers.IO) {
mHistoryDao.getAll().collect {
withContext(Dispatchers.Main){
//更新ui
}
}
}
}
collect
是Flow
获取数据的方式,并不是唯一方式,可以查看文档。
为什么放在协程
里面呢,因为数据库的操作是费时的,而协程可以轻松的指定线程,这样不阻塞UI
线程。
查看Flow源码也发现,Flow是协程包下的
package kotlinx.coroutines.flow
以collect为例,也是被suspend
修饰的,既然支持挂起
,那配合协程
岂不美哉。
@InternalCoroutinesApi
public suspend fun collect(collector: FlowCollector)
保存搜索记录
private fun saveSearchHistory(text: String) {
MainScope().launch(Dispatchers.IO) {
mHistoryDao.insert(History(null, text, DateUtils.longToString(System.currentTimeMillis())))
}
}
清空本地历史
private fun cleanHistory() {
MainScope().launch(Dispatchers.IO) {
mHistoryDao.deleteAll()
}
}
数据库升级
================================================================
数据库升级是一个重要的操作,毕竟可能会造成数据丢失,也是很严重的问题。
Room通过Migration
类来执行升级的操作,我们只要告诉Migration
类改了什么就行,比如新增
字段或表。
定义Migration类
/**
- 数据库版本 1->2 t_history表格新增了updateTime列
*/
private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(“ALTER TABLE t_history ADD COLUMN updateTime String”)
}
}
/**
- 数据库版本 2->3 新增label表
*/
private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(“CREATE TABLE IF NOT EXISTS t_label
(id
INTEGER PRIMARY KEY autoincrement, name
TEXT)”)
}
}
Migration
接收两个参数:
-
startVersion 旧版本
-
endVersion 新版本
通知数据库更新
mPersonDatabase = Room.databaseBuilder(
context.applicationContext,
HistoryDatabase::class.java,
DATABASE_NAME
).addMigrations(MIGRATION_1_2, MIGRATION_2_3)
.build()
完整代码
@Database(entities = [History::class, Label::class], version = 3)
abstract class HistoryDatabase : RoomDatabase() {
abstract fun historyDao(): HistoryDao
companion object {
private const val DATABASE_NAME = “history.db”
private lateinit var mPersonDatabase: HistoryDatabase
fun getInstance(context: Context): HistoryDatabase {
if (!this::mPersonDatabase.isInitialized) {
//创建的数据库的实例
mPersonDatabase = Room.databaseBuilder(
context.applicationContext,
HistoryDatabase::class.java,
DATABASE_NAME
资源分享
点击:
**《Android架构视频+BAT面试专题PDF+学习笔记》**即可免费获取
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
ISBi-1643959028573)]
[外链图片转存中…(img-P3bSSABh-1643959028574)]
[外链图片转存中…(img-UTMnsowi-1643959028575)]
点击:
**《Android架构视频+BAT面试专题PDF+学习笔记》**即可免费获取
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。