https://kotlinlang.org logo
a

ahulyk

11/19/2019, 9:58 AM
Have a short question here. The usage of Courotines inside UseCase is bad practice?
g

ghedeon

11/19/2019, 10:41 AM
Why? Bring coroutines all the way up to ViewModel and subscribe there.
a

ahulyk

11/19/2019, 10:58 AM
And what about passing coroutine scope to UseCase?
g

ghedeon

11/19/2019, 11:42 AM
Sometimes it makes sense, if the caller is still in Java for example. But it complicates passing the result back to VM. It's asynchronous, so you'd need a callback or LiveData/Rx/Flow.
s

sergio250

11/19/2019, 11:46 AM
I’d never rely on use cases deciding where to be executed and rather let the callers choose the context where they want to execute stuff. That way you avoid having sync/async use cases
i

ibraiz_teamo

11/19/2019, 12:21 PM
this is my usecase class:
Copy code
abstract class SuspendUseCase<out Type, in Params> where Type : Any {

    abstract suspend fun run(params: Params): Either<Failure, Type>

    operator fun invoke(scope: CoroutineScope, params: Params, onResult: (Either<Failure, Type>) -> Unit = {}) {
        val job = scope.async { run(params) }
        scope.launch(Dispatchers.Main) { onResult(job.await()) }
    }

    class None
}
how can this be furthered improved? Or there should be different suspend usecase classes for IO, Compute and non-blocking usecases?
a

ahulyk

11/19/2019, 1:32 PM
Passing result back can be done by Callback/LiveData/Rx - question is more about philosophy :)
u

ursus

11/19/2019, 1:57 PM
@ghedeon how would you then have action that doesnt get canceled on viewmodel getting killed?
g

ghedeon

11/19/2019, 2:00 PM
That would be responsibility of the scope that owns the lifecycle of that action.
u

ursus

11/19/2019, 2:17 PM
true, but how do you make it work if usecase.execute() is a plain suspend function without explicit scope? (i.e in caller scope)
g

ghedeon

11/19/2019, 3:41 PM
that doesn't mean that it's all executed in caller scope tho. You can easily have
usecase() -> foo.bar()
where
bar
is called on whatever scope was injected into
foo
.
kind of similar to launching a separate
CoroutineScope().launch{}
inside of suspend function (just not structured in this case).
u

ursus

11/19/2019, 3:49 PM
so you'd inject appScope instance into the use case?
g

gildor

11/19/2019, 11:34 PM
Depends on case. This is "structured" concurrency, structure hierarchy of scopes depending on use case and required semantics
👍 1
u

ursus

11/19/2019, 11:35 PM
Yes but im still unsure about scope as a parameter, shouldnt it be a impl. detail of such component?
g

gildor

11/22/2019, 2:36 PM
If it is implementation detail of such component, it should have lifecycle of this component too. If scope lives longer than the component, than it should be a constructor param. If component doesn't have own lifecycle, it just should be suspend function (or a function with scope as receicer/argument) in component, so it will use caller scope instead
1
u

ursus

11/22/2019, 5:09 PM
@gildor If you pass it in as ctor param, to a component that has a shorter lifecycle than the scope instance passed in, isnt that a memory leak?
also, im not very sure about it. one precedence for it already is in view - viewModel. And view doesnt have viewModel scope passed in, and nobody complains
g

gildor

11/22/2019, 5:15 PM
It's not necessary memory leak, but you can create one, depends on what you do in such coroutine, it's true. Suspend functions is safest way for sure
u

ursus

11/22/2019, 5:18 PM
well if appScope is injected into viewModel, afaik then if used it will hold reference ti the viewModel until suspend function completes, even when viewModel's onCleared was called
g

gildor

11/23/2019, 2:38 AM
No, it's incorrect, it will hold reference only if you use viewModel members in this coroutine after suspend But as we already discussed with you previously. Im not advocating for this approach, especially for components which already have own lifecycle and even own scope out of the box. Pretty sure in 99% cases you should just use viewModel coroutineScope for background tasks. If you need tasks that run longer than viewModel... Than do not add them to view model
6 Views