https://kotlinlang.org logo
#coroutines
Title
# coroutines
m

Michał Kalinowski

07/05/2020, 3:02 PM
Hey, is there any way to pass e.g coroutine scope from suspended function to normal function and then invoke another suspend function on this scope? For example:
Copy code
suspend fun fooA(){
  coroutineScope {
    fooB(this)
  }
}

fun fooB(coroutineScope: CoroutineScope){
  continueWithSuspend(coroutineScope){
    continueSuspendingFooA()
  }
}

private suspend fun continueSuspendingFooA(){}
e

Erik

07/05/2020, 4:40 PM
Why make fooB accept a coroutine scope? If you do that, why not write it as a suspending function or as an extension of coroutine scope?
m

Michał Kalinowski

07/05/2020, 7:23 PM
This is a simple example, in practice I would like to write some type of extension for a live date such as
fun <T : Any> LiveData<T>.observeWithSuspend(observer: suspend (data: T) -> Unit)
, which I could call when creating View :<, When liveData make a dispatch it would suspend the scope it is in, until all jobs are done
a

araqnid

07/06/2020, 9:07 AM
In any suspending function, you can access the
coroutineContext
intrinsic. A coroutine scope is essentially just a wrapper around that:
CoroutineScope(coroutineContext)
m

Michał Kalinowski

07/06/2020, 10:19 AM
@araqnid Thanks! It's works 🙂:
Copy code
suspend fun fooA(){
    coroutineScope {
        println("we start here")
        fooB(coroutineContext)
        println("and end here after 1s :)")
    }
}
fun fooB(coroutineContext: CoroutineContext){
    runBlocking(coroutineContext) {
        continueSuspendingFooA()
    }
}
private suspend fun continueSuspendingFooA(){
    delay(1000)
}
m

myanmarking

07/07/2020, 8:48 AM
runBlocking does nothing there i think. Why do you need it ?
why not just make the 2nd and third suspend and be done with it ? I'm curious about your usecase, can you tell me more about it please?
m

Michał Kalinowski

07/07/2020, 9:49 PM
@myanmarking runBlocking is currently blocking the scope that is in fooA() 🙂
and now it applies quite primitive, let's say I have View.onViewCreated() and ViewModel which has my LiveDate and some CoroutineScope on which it works, and now inside the View.onViewCreated() function (which is not a suspend function) I want to liveData to observe some suspend function so that every time I call it, it will blocks the scope
Generally speaking, all thing it's about making an observer who can suspend a certain scope when notified
Unfortunately, I can only give you something like "pseudocode" as example:
Copy code
// some simplified LiveData methods(observe and observeWithSuspend) without lifecycle: 
fun observe(observer: LiveDataObserver<T>) {
    observers.add(observer)
}

fun <T : Any> LiveData<T>.observeWithSuspend(
        context: CoroutineContext,
        observer: suspend (data: T) -> Unit
) {
    observe {
        runBlocking(context) {
            observer(it)
        }
    }
}

// Our viewModel
class SomeViewModel(){
    val someJobScope = CoroutineScope(Dispatchers.Default)
    // LiveData will block scope in a way that first will be performed points in order 1. 2. 3. 4.
    val someLiveData = MutableLiveData<Position>()

    //function that set our liveData
    private fun handleCoordinate(position: Position) {
        someJobScope.launch {
            // 1.
            someLiveData.value = position // 2.
            // 4
        }
    }
}

// Our activity/fragment
class SomeActivity(){
    val viewModel: SomeViewModel // our viewModel
    val someCoordinator: SomeCoordinator // our coordinator that will be observed and will suspend viewModel.someJobScope when notified

    override fun onViewCreated() {
        viewModel.someLiveData.observeWithSuspend(viewModel.someJobScope.coroutineContext) { position ->
            // 3
            someCoordinator.performSomeActionWithSuspend(position) // some suspended function to work with coordinator!
        }
    }
}
3 Views