【问题标题】:How to return value in coroutine scope?如何在协程范围内返回值?
【发布时间】:2022-07-05 23:41:37
【问题描述】:

是否可以在不阻塞运行的情况下返回 Coroutine Scope 中的值? 现在我在存储库中的代码如下所示:

    suspend fun getWorkItem(workItemId: Int): WorkItemRoom? {
        runBlocking {
            return@runBlocking
            CoroutineScope(Dispatchers.Main).launch {
                getWorkItemByIdUseCase.build(workItemId)
            }
        }
        return null
    }

这是我的用例

class GetWorkItemByIdUseCase(private val workItemDao: WorkItemDao) :
    BaseUseCase<Int, WorkItemRoom>() {
    override suspend fun create(id: Int): WorkItemRoom {
        return workItemDao.getWorkItemById(id)
    }

}

基本用例

abstract class BaseUseCase<P, R> {
    protected abstract suspend fun create(params: P): R
    open suspend fun build(params: P): R = create(params)
}

@Dao
abstract class WorkItemDao {

    @Query("SELECT * FROM workitem WHERE id=:id")
    abstract suspend fun getWorkItemById(id: Int): WorkItemRoom
}

...但我当然知道这不是一个合适的解决方案。您将如何实现这一目标?在viewmodels' or fragments I can directly use lifecycleScope` 中,但在其他情况下,必须直接从下面的方法调用 useCase。一直调用 Dispatchers.Main 效率高吗?

CoroutineScope(Dispatchers.Main).launch { }

【问题讨论】:

    标签: android kotlin kotlin-coroutines


    【解决方案1】:

    在挂起函数中使用runBlocking 没有意义。 (使用它几乎没有任何意义,除非在项目中作为协程和非协程代码之间的桥梁,该项目部分转换为使用协程但仍需要支持遗留代码或库。)

    你应该调用你需要的函数。

    suspend fun getWorkItem(workItemId: Int): WorkItemRoom? { //may not need nullable return value
        return getWorkItemByIdUseCase.build(workItemId)
    }
    

    如果需要指定调度器,使用withContext:

    suspend fun getWorkItem(workItemId: Int): WorkItemRoom? = withContext(Dispatchers.Main) { 
        getWorkItemByIdUseCase.build(workItemId)
    }
    

    但是,如果build 是一个挂起函数,则在调用它时无需指定 Dispatcher。挂起函数负责在适当的线程/调度程序上内部调用它们的函数。

    如果您需要协程或挂起函数内的协程作用域,请使用小写的coroutineScope 函数。这个例子没有多大意义,因为通常你不需要一个新的范围,除非你在其中运行并行作业:

    suspend fun getWorkItem(workItemId: Int): WorkItemRoom? = coroutineScope(Dispatchers.Main) { 
        getWorkItemByIdUseCase.build(workItemId)
    }
    

    【讨论】:

      【解决方案2】:

      您可以将值从协程传递给 liveData,然后使用观察者

      private val observableMutableLiveData = MutableLiveData<Type>()
      val observableLiveData: LiveData<Type> = observableMutableLiveData
      

      后来在协程中:

      CoroutineScope(Dispatchers.Main).launch {
          observableMutableLiveData.postValue(value)
      }
      

      然后在一个活动中:

      viewModel.observableLiveData.observe(this) { Type ->
         Log.i("result", Type)
      }
      

      【讨论】:

        【解决方案3】:

        你听过 lambda 吗?
        看起来像call: (MyResult) -&gt; Unit
        我不时使用它像

        fun someToDo(call: (MyResult) -> Unit) {
            scope.launch(Dispatchers.IO) {
                val result = getFromSomeWere()
                launch(Dispatchers.Main){call(result)}
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2020-11-07
          • 2020-06-23
          • 2023-01-27
          • 2021-08-17
          • 1970-01-01
          • 1970-01-01
          • 2020-07-09
          • 2019-05-20
          • 1970-01-01
          相关资源
          最近更新 更多