naively, if coroutines transform into callbacks, t...
# coroutines
u
naively, if coroutines transform into callbacks, then those do have reference to the outer class, so it should leak, right?
m
yes, your
view
will be kept until scope is canceled or coroutine completes
u
not only
view
, but whole
this
(viewModel) right?
m
it depends on what you reference inside coroutine block, if
view
was a variable inside
doSomething()
fun it shouldn't leak entire ViewModel (someone correct me if I'm wrong), not sure what happens if
view
is a property (it will probably keep reference to this/ViewModel to access it)
v
Performing any long running operation inside
globalScope.launch
will cause a leak if the operation is not completed when VM is disposed.
u
yes but what is leaking? I think whole viewmodel instance since callback, anonymous class will have reference to the enclosing class = viewmodel
l
You would leak memory AND CPU if the coroutine (code inside it) keeps running after it should be cancelled. That's why there's a
viewModelScope
in KTX artifact (which is possibly still in beta/rc).
v
@ursus You would be leaking VM
u
@louiscad well intention is exactly that, to keep operation going, regardless if UI is there; but yes ui needs to detach it self from the callback
l
@ursus You should use WorkManager if work can fail and needs to be retried.
u
@louiscad not really, its a general layering issue, ui triggers an action in domain and only observes the results, (this some syncing use case), dont think some android api is needed to be concrete its the chris banes Tivi app, https://github.com/chrisbanes/tivi/pull/397, you may want to comment
so correct me if im wrong there
l
Oh, this PR is okay. It's using the ProcessLifecycleOwner that gets cancelled once all activities are destroyed, and it's launching in this scope, joining the jobs from UI scope (that is cancelled in time as needed). You can
join
a
Job
`launch`ed from another scope, and cancelling the coroutine calling
join
should not cancel the
Job
.
u
well, thats leaking anyways I believe, if it gets canceled once ALL activities are gone?
why not just have the each layers own their scope? something like
Copy code
suspend fun doSomething(): String = scoped x@{
        delay(2000)
        Log.d("Default", "returning something")
        foo()
        Log.d("Default", "returning something 2")
        return@x "Something"
    }
priva

te suspend fun <T> scoped(body: suspend CoroutineScope.() -> T): T {
        val deferred = scope.async(block = body)
        return deferred.await()
    }
l
Well, you definitely don't want to run long or possibly background repeating tasks in this scope.
u
well, if by background you mean app not in foreground, then even viewModelScope wont help you but okay thanks for help; I still think injecting scope is bad idea, domain should decide that, not ui
l
True. You may want a narrower scope. With the
createScope(activeWhile = <http://Lifecycle.State.XXX|Lifecycle.State.XXX>)
extension function for
Lifecycle
, you can have it, even for
ProcessLifecycle
. You can find that extension here: https://github.com/LouisCAD/Splitties/tree/master/modules/lifecycle-coroutines
u
So, in general, do you think scope should be a ctor parameter of forexample Repository? Or private impl detail
l
Depends if you need to scope the repository or if it's global or almost global (e.g. scoped to a user session or to an account)
u
scoped to account logged in