在完成了一套viewmodel的代码后,相信后续的大家也能照猫画虎的写出来了,但是现在又产生了新的问题,我要如何将数据库中的数据实时显示在列表中呢?
这时候就要用到Flow这个东西了,或者LiveData都行,这里就用Flow了。
然后还要做一下区分:
创建小说是在FictionNamePage中,但是显示列表是在MainPage中,所以我们要先给MainPage也来一套viewmodel,然后再考虑它的列表显示问题。
直接上代码
@Dao
interface MainPageDao {
@Delete
suspend fun deleteBook(book: Book)
//获取所有书列表,用于列表显示
@Query("SELECT * FROM fictionData ORDER BY fiction_id DESC")
fun getAllBooks(): Flow>
//获取一本书的id号,用于后续删除
@Query("SELECT * FROM fictionData WHERE fiction_id = :idF")
suspend fun getBookOfId(idF: Int): Book?
}
这里可以看到第二条代码,就是以Flow的形式声明的,之后我们要通过它来实时刷新我们的列表。
这里只需要加一句话
abstract fun mainPageDao(): MainPageDao
interface MainPageRepository {
suspend fun deleteBook(book: Book)
//获取所有书列表,用于列表显示
fun getAllBooks(): Flow>
//获取一本书的id号,用于后续删除
suspend fun getBookOfId(idF: Int): Book?
}
这个和上篇一样,没啥好说的。
class OfflineMainPageRepository(private val mainPageDao: MainPageDao) : MainPageRepository {
override suspend fun deleteBook(book: Book) = mainPageDao.deleteBook(book)
//获取所有书列表,用于列表显示
override fun getAllBooks(): Flow> = mainPageDao.getAllBooks()
//获取一本书的id号,用于后续删除
override suspend fun getBookOfId(idF: Int): Book? = mainPageDao.getBookOfId(idF)
}
用来将两个接口接起来的函数。
class MainPageViewModel(private val mainPageRepository: MainPageRepository) : ViewModel() {
//用于列表显示
fun getAllBooks(): Flow> {
return mainPageRepository.getAllBooks()
}
//删除某一本书,或者某一章节
fun deleteBookAndAll(id:Int){
viewModelScope.launch {
val deleteBook = mainPageRepository.getBookOfId(id)
mainPageRepository.deleteBook(deleteBook!!)
}
}
}
可以看到有关Flow的函数返回值一直是Flow类型的。
interface AppContainer {
val mainPageRepository: MainPageRepository
val fictionNameRepository: FictionNameRepository
}
/**
* [AppContainer] implementation that provides instance of [OfflineItemsRepository]
*/
class AppDataContainer(private val context: Context) : AppContainer {
/**
* Implementation for [ItemsRepository]
*/
override val mainPageRepository: MainPageRepository by lazy {
OfflineMainPageRepository(AppDatabase.getInstance(context).mainPageDao())
}
override val fictionNameRepository: FictionNameRepository by lazy {
OfflineFictionNameRepository(AppDatabase.getInstance(context).fictionNameDao())
}
}
完全按照上一篇做而已。
object AppViewModelProvider {
val Factory = viewModelFactory {
initializer {
MainPageViewModel(
fictionApplication().container.mainPageRepository
)
}
initializer {
FictionNameViewModel(fictionApplication().container.fictionNameRepository)
}
}
}
到这里为止基本上ViewModel就写好了,接下来到页面中去写实现方法。
fun MainPage(navController: NavController,
viewModel: MainPageViewModel = viewModel(factory = AppViewModelProvider.Factory)
)
val book = remember {
mutableListOf()
}
这里我声明了一个Book类型的可变List,然后remember字段就是为了全局保存,以防横竖屏切换之类的动作导致获取的数据丢失。
val books = viewModel.getAllBooks().collectAsState(initial = book).value
首先,我们在最开始的Dao中写的getAllBooks函数是一个非主线程函数,他不能在主线程里运行,因此就要用到collectAsState字段将获取到的 Flow>
值转换为 State>
而State想要获取其中的值,就可以用.value方法来获取。
此时的books就是List
这个时候,我们获取的每个it都是一个Book类型的数据类。我们只需在Text中使用it.的方式就能获取其中定义好的参数。
这时,我们的列表实时刷新就完成了,测试一下!
注意:
经过多次测试发现这是因为点击加号后跳转到新页面,在新页面操作完成后再跳转回旧页面的时候,自动触发了Compose,如果是在当前页面进行实时操作,那么列表将不会实时刷新。