Can somebody help me understand why I'm getting "k...
# coroutines
t
Can somebody help me understand why I'm getting "kotlinx.coroutines.JobCancellationException: Parent job is Completed" when I try to start my web service in my view model? I'm trying to delay the connection until after I have an auth token so that the connect will be successful.
a
Catching
Throwable
and not rethrowing is likely breaking cancellation
This code also looks like it can and will start multiple concurrent connection attempts, which is unlikely to be what you want
t
That is correct. I would only want to connect if not connected. I would add a check to skip if already connected. The block catching the exception shouldn't cause the JobCancellationException, right?
a
A cancellation exception is normal in viewModelScope, ViewModel clear cancels the scope's job
It's the natural mechanism used to stop viewModelScope work
But by catching it you're preventing that graceful teardown so your flow doesn't stop collecting
t
Gotcha. I can re-throw. Right now I'm getting the cancellation exception on line 10 when trying to connect to the web service. What would be the correct way to launch another coroutine based on the value returned from a flow?
j
How come you're using
async
when you do nothing with the
Deferred
returned? Also, if you're interested in just one value from
userState
, and it's a
Flow
why not just
take(1)
, instead of wrapping in
collect
? Also, as is,
viewModelScope.launch
and
viewModelScope.async
will run concurrently. Wouldn't you prefer the inner coroutine to be a child of the outer one? That way cancelling the job of the outer one would automatically cascade down to cancel the inner one?
t
There was other initialization stuff in the init block that I removed. Without async the other stuff would be blocked. I could move that other stuff out and launch that separately. I'm interested in this for when the user logs out / back in too, so I want to continue collecting. Any idea why I'm getting the parent job completed exception? I've overrode onCleared() in my view model and it isn't called. I'm not sure why the job would be completed.
j
The only parent job evident from what you've shared is the job of the
viewModelScope
itself, which is a
SupervisorJob
. I don't see how that could have completed if
onCleared
was never called. Are there any other parent-child job relationships in play that we can't see from the code given? The exception suggests that you're trying to do something with a job whose parent has completed. Question is... which parent job is that?
Are you using a custom
viewModelScope
that doesn't use a
SupervisorJob
?
t
It is just the regular viewModelScope. One strange thing that I noticed is that if I switch the uiState to use a SharedFlow instead of a StateFlow, this code works. The problem with using a SharedFlow is that updating the state for logout doesn't work. It just suspends and never updates the ui state.
j
How many times is
collect
called before the exception occurs?
t
Twice. Login, logout, then logging back in causes the exception. So on the third UserState with isLoggedIn set to true.
j
Is it possible that
webService
is still connecting when
disconnect
is called? If so, how does
webService
behave in this situation? I assume
connect
and
disconnect
are not
suspend
functions. Is that right?
t
The web service is using HttpClient from ktor. It loops forever in the DefaultClientWebSocketSession when you open the request until close is called on the HttpClient instance. I think that closing that client is related somehow.
513 Views