简体   繁体   中英

How to return value in coroutine scope?

Is it possible to to return value in Coroutine Scope without run blocking? For now my code in repository looks like this:

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

this is my useCase

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

}

baseUseCase

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

Dao

@Dao
abstract class WorkItemDao {

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

... but certainly I know it is not a proper solution. How would you achieve this? In viewmodels' or fragments I can directly use lifecycleScope`, but what in other cases, where the must is to call useCase directly from method below. Is it efficient to call Dispatchers.Main all the time?

CoroutineScope(Dispatchers.Main).launch { }

It doesn't make sense to use runBlocking in a suspend function. (It hardly ever makes sense to use it at all, except as a bridge between coroutines and non-coroutine code in a project that is partially converted to using coroutines but still needs to support legacy code or libraries.)

You should just call the function you need.

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

If you need to specify a dispatcher, use withContext :

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

However, if build is a suspend function, there's no need to specify a Dispatcher when calling it. Suspend functions are responsible for internally calling their functions on appropriate threads/dispatchers.

If you need a coroutine scope inside a coroutine or suspend function, use the lowercase coroutineScope function, which creates a scope that will be automatically cancelled if the coroutine is cancelled. This example doesn't make much sense, because normally you don't need a new scope unless you are running parallel jobs inside it:

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

You could just pass the value from a coroutine to liveData and then use an observer

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

and later in a coroutine:

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

and then in an activity:

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

Have you ever listened about a lambda ?
It looks like call: (MyResult) -> Unit
I use it from time to time like

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM