Kotlin 如何使用协程从文件室返回单个(非LiveData)对象
Room在后台线程上自动执行返回Kotlin 如何使用协程从文件室返回单个(非LiveData)对象,kotlin,android-room,android-livedata,android-architecture-components,kotlin-coroutines,Kotlin,Android Room,Android Livedata,Android Architecture Components,Kotlin Coroutines,Room在后台线程上自动执行返回LiveData的查询。但是我想返回一个没有包装到LiveData中的值(因为我不想要实时更新)。 如何使用协同程序实现这一点 如何从此函数返回任务对象 fun getTask(id: Int): Task { viewModelScope.launch { repository.getTask(id) } } 此函数位于ViewModel内部。它将调用转发给DAO: @Query("SELECT * FROM task_tabl
LiveData
的查询。但是我想返回一个没有包装到LiveData
中的值(因为我不想要实时更新)。
如何使用协同程序实现这一点
如何从此函数返回任务
对象
fun getTask(id: Int): Task {
viewModelScope.launch {
repository.getTask(id)
}
}
此函数位于ViewModel内部。它将调用转发给DAO:
@Query("SELECT * FROM task_table WHERE id = :id")
fun getTask(id: Int): Task
如果您不从文件室返回LiveData,您将无法从数据库获得更新。但是,您可以从viewModel返回LiveData
val data = liveData {
emit(repository.getTask(id))
}
liveData
扩展函数在一个协同程序中运行,然后您可以使用DAO的挂起版本来正确处理后台处理
@Query("SELECT * FROM task_table WHERE id = :id")
suspend fun getTask(id: Int): Task?
如果您在查询中不使用聚合函数,那么需要做的一件大事是确保它可以为null
如果确实希望调用viewModel中的方法以返回任务,则应从活动/片段运行启动(不推荐)
解决方法之一是立即返回延迟对象,然后在返回延迟对象时调用
.await()
fun getTaskAsync(id:Int):Deferred=viewModelScope.async{
repository.getTask(id)
}
//呼叫站点
getTaskAsync(id).await()//流是新的LiveData!
我以前在两个项目中遇到过类似的问题,每个问题的解决方式都不同。但最近我学会了使用Flow
,这似乎是迄今为止最干净的方法
LiveData的替代方案
如果不需要使用LiveData,您有两个选择:
游标
,适用于重构旧项目流程
,适用于新项目流
:
片段/活动:
特性:
private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
当不需要片段/活动时,不要忘记取消viewModelJob,例如onClear/onDestory/。。。所以所有与此紧密相关的协同程序都被取消了
用法
现在,每当我们想要从挂起的函数中检索对象任务时,我们都需要在挂起或协同例程中。因此,在这里使用launch
builder来创建协同程序是合适的(因为我们不希望从该构建器返回任何对象,我们只希望运行一个挂起函数,否则异步返回一个延迟的对象)
如果我们不使用first()
,那么我们需要收集流viewModel.getTasks().collect{it}
,这里有很多有用的函数<代码>流是协同程序包中发生的最好的事情,哦,很抱歉我通过了存储库层,在大多数情况下,它只是viewModel的副本
房间中的挂起功能是主要的安全功能,并在定制的计算机上运行
调度员。与您在问题中提到的LiveData相同。下面是实现相同目标的示例
在viewmModel类中的某个函数内
在存储库类中
suspend fun getSomething():列表{
return dao.getSomething()
}
道课
@Query(“从tableName中选择*)
suspend fun getSomething():列表
您不能从协同程序进行同步(立即)返回。他们不是这样工作的。协同程序是异步的,其数据的消耗一直异步到最终使用者。这就是LiveData存在的原因——使用它,即使你认为它太复杂了。@DougStevenson感谢你的回答。我不想使用LiveData
的原因是这个值不应该在屏幕上得到实时更新。我想我仍然可以返回LiveData
并只读取它的值
一次,但这似乎不是一个干净的解决方案。毕竟,它被称为live data。对于单个响应来说,live data是一个非常好的解决方案。事实上,文档甚至用它的“资源”模式证实了这一点。好的,谢谢。关于您提到的文档部分,您是否有可以指向我的链接?@Query(…)suspend fun getTask(id:Int):Task
,您也可以将Flow
与Room
一起使用,而不是LiveData
。问题是如何从supsend函数返回值
@Query("SELECT * FROM task_table WHERE id = :id")
fun getTask(id: Int): Flow<Task>
suspend fun getTask(id: Int): Task {
return dao.getTask(id).first()
}
private var viewModelJob = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
onCreate() / onCreateView()
.
..
...
uiScope.launch() {
// Here are the Task & Main-UI
val task = viewModel.getTask(1)
binding.taskTitleTextView.text = task.title
}
viewModelScope.launch {
// suspend and resume make this database request main-safe
// so our ViewModel doesn't need to worry about threading
someLiveData.value =
repository.getSomething()
}
suspend fun getSomething(): List<Something> {
return dao.getSomething()
@Query("select * from tableName")
suspend fun getSomething(): List<Something>