Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 如何使用协程从文件室返回单个(非LiveData)对象_Kotlin_Android Room_Android Livedata_Android Architecture Components_Kotlin Coroutines - Fatal编程技术网

Kotlin 如何使用协程从文件室返回单个(非LiveData)对象

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

Room在后台线程上自动执行返回
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,您有两个选择:

  • 通过@query检索
    游标
    ,适用于重构旧项目
  • 使用
    流程
    ,适用于新项目
  • 仅检索一个对象/值
  • LiveDate:您可以取消订阅LiveData,在第一次获取后删除观察者。在我看来,这不是干净的方式
  • 流:如果需要,可以只检索单个对象/值,然后停止流收集
  • Dao: getTask():此方法返回

    片段/活动: 特性:

    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>