Is there a recommended way, how to use suspending ...
# mvikotlin
b
Is there a recommended way, how to use suspending code in Decompose
componentContext
? Should it contain a new CoroutineScope or should it expose suspending functions and the component should handle it (e. g. with
rememberCoroutineScope
)?
a
I recommend the former option. You can add the following builder function:
Copy code
fun CoroutineScope(context: CoroutineContext, lifecycle: Lifecycle): CoroutineScope {
    val scope = CoroutineScope(context)
    lifecycle.doOnDestroy(scope::cancel)

    return scope
}
And then use it as follows:
Copy code
class SomeComponent(componentContext: ComponentContext): ComponentContext by componentContext {
    private val scope = CoroutineScope(Dispatchers.Main, lifecycle)
}
🙂 1
👍 2
f
really nice approach
b
@Arkadii Ivanov Do I understand it right, that we should not expose suspending functions? That would mean, that testing would be really hard, when internally scope.launch is used due to the not-suspending functions.
a
@benkuly I don't get the part "when internally scope.launch is used due to the not-suspending functions". But the main point is as follows. When a suspending function is exposed, then it is the caller's controls the scope. E.g. if you call the function from a
@Composable
function, then it will be bound to the composition's lifecycle. When push another screen to the stack, the scope will be cancelled. In most of the cases we want jobs bound to component lifecycles instead. And the point about testing is yet another one. Testing normal functions is always simpler. You can pass "main" context via constructor, so in production it will be
Dispatchers.main
, and in tests you can use e.g.
Dispatchers.unconfined
.
Copy code
class SomeComponent(
    componentContext: ComponentContext,
    mainContext: CoroutineContext = Dispatchers.main,
) { ... }
b
I meant, that e. g. the calling suspending code from a not suspending function is only possible with
scope.launch
. So in the test, when the function is called, it return immediatly and we have to find a way to wait until the code within the
scope.launch
has finished. I don't know a nice way to do that.
a
You need to pass different context via constructor, and so to the scope. In tests you can use Unconfined dispatcher, which execute your
launch
synchronously. If you target only Android, the you can use
TestDispatcher
, which provides ability to manually control execution.
👍 1