David Ng
10/01/2020, 10:47 AMclass profileViewModel: ViewModel() {
val profileRepository: ProfileRepository
fun subscribeToProfile(id: Int) {
viewModelScope.launch {
profileRepository.subscribeToProfile(id)
}
}
}
My repository class
class ProfileRepository {
fun subscribeToProfile(id: Int) {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
..... // Does this get cancelled onCleared()?
}
}
}
It seems to me the function in repository class still running despite I've navigated away from Profile Fragment.
I've tried to debug on the view model and override the onCleared() function and call .cancel()
override fun onCleared() {
super.onCleared()
viewModelScope.cancel()
}
I was able to breakpoint in onCleared()
and execute the .cancel()
but it doesn't cancel the job in repository.
Am I missing any steps here?David Ng
10/01/2020, 10:58 AMwithContext
is a flow, the flow is still collecting after the viewModelScope
is cancelled. Doing some google search shows I need to explicitly cancel the flow as well?gildor
10/01/2020, 11:18 AMfun subscribeToProfile(id: Int) {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
it’s invalid code, subscribeToProfile must be suspend to use withContextgildor
10/01/2020, 11:20 AMshows I need to explicitly cancel the flow as wellWhat kind flow?
gildor
10/01/2020, 11:20 AMDavid Ng
10/01/2020, 11:23 AMgildor
10/01/2020, 11:24 AMDavid Ng
10/01/2020, 11:24 AMflow<UserProfile>()
which I store/update my current user profile locallygildor
10/01/2020, 11:25 AMgildor
10/01/2020, 11:26 AMDavid Ng
10/01/2020, 11:26 AMstub.subscribeToUserProfile(request)
.asFlow()
.collect { updateUserProfile(it) }
David Ng
10/01/2020, 11:27 AMDavid Ng
10/01/2020, 11:27 AMgildor
10/01/2020, 11:27 AMviewModelScope.cancel()
it looks unnecessary, standard built-in view model scope cancelled automatically onClearedgildor
10/01/2020, 11:28 AMdo I need to explicitly cancel the flowNo, collect is cancellable suspend function, flow will be cancelled if collect is cancelled
gildor
10/01/2020, 11:28 AMgildor
10/01/2020, 11:29 AMDavid Ng
10/01/2020, 11:30 AMDavid Ng
10/01/2020, 11:31 AMDavid Ng
10/01/2020, 11:40 AM.collect {
cancel()
}
But it's still collectingDavid Ng
10/01/2020, 11:41 AMgildor
10/01/2020, 2:37 PMDavid Ng
10/02/2020, 9:52 AMclass profileViewModel: ViewModel() {
val profileRepository: ProfileRepository
fun subscribeToProfile(id: Int) {
viewModelScope.launch {
profileRepository.subscribeToProfile(id)
}
}
}
class ProfileRepository {
suspend fun subscribeToProfile(id: Int) {
withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
val channel = ManagedChannelBuilder.forAddress(serviceUrl, 5001)
.usePlaintext()
.build()
val stub = UserProfileGrpc.newBlockingStub(channel)
val request = SubscribeUserProfileRequest
.newBuilder()
.setId(id)
.build()
stub.subscribeToUserProfile(request)
.asFlow()
.collect { updateUserProfile(it) }
}
}
}
David Ng
10/02/2020, 9:56 AMgildor
10/02/2020, 10:56 AMgildor
10/02/2020, 10:57 AMgildor
10/02/2020, 10:57 AMDavid Ng
10/02/2020, 11:01 AMDavid Ng
10/02/2020, 11:02 AMwithContext(<http://Dispatchers.IO|Dispatchers.IO>)
would make sure the following code executes in IO thread insteadgildor
10/02/2020, 11:03 AMDavid Ng
10/02/2020, 11:03 AMgildor
10/02/2020, 11:03 AMgildor
10/02/2020, 11:03 AMDavid Ng
10/02/2020, 11:04 AMgildor
10/02/2020, 11:05 AMgildor
10/02/2020, 11:05 AMgildor
10/02/2020, 11:06 AMDavid Ng
10/02/2020, 11:06 AMgildor
10/02/2020, 11:06 AMDavid Ng
10/02/2020, 11:06 AMgildor
10/02/2020, 11:06 AMgildor
10/02/2020, 11:07 AMDavid Ng
10/02/2020, 11:07 AMgildor
10/02/2020, 11:07 AMgildor
10/02/2020, 11:07 AMDavid Ng
10/02/2020, 11:07 AMgildor
10/02/2020, 11:08 AMDavid Ng
10/02/2020, 11:08 AMgildor
10/02/2020, 11:08 AMgildor
10/02/2020, 11:09 AMDavid Ng
10/02/2020, 11:10 AMstreamObserver
along with the requestgildor
10/02/2020, 11:11 AMDavid Ng
10/02/2020, 11:11 AMDavid Ng
10/02/2020, 11:11 AMgildor
10/02/2020, 11:11 AMDavid Ng
10/02/2020, 11:11 AMDavid Ng
10/02/2020, 11:12 AMDavid Ng
10/02/2020, 11:12 AMDavid Ng
10/02/2020, 11:13 AMgildor
10/02/2020, 11:13 AMgildor
10/02/2020, 11:13 AMgildor
10/02/2020, 11:13 AMDavid Ng
10/02/2020, 11:15 AMDavid Ng
10/03/2020, 1:21 AMclass profileViewModel: ViewModel() {
val profileRepository: ProfileRepository
fun subscribeToProfile(id: Int) {
viewModelScope.launch {
profileRepository.subscribeToProfile(id)
}
}
}
class ProfileRepository {
suspend fun subscribeToProfile(id: Int) {
val stub = UserProfileGrpc.newStub(channel)
// Build request
stub.subscribeToUserProfile(request, object: StreamObserver<UserProfile> {
override fun onNext(value: UserProfile?) {
CoroutineScope(coroutineContext).launch { // This is correct? updateUserProfile is a suspend fun
updateUserProfile(value)
}
}
})
}
}
I tried CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>)
and it works, but it has the same profile, the updateUserProfile()
still get executed when I navigate away from profile fragmentDavid Ng
10/03/2020, 2:50 AMUserProfileGrpcKt.UserProfileCoroutineStub
which is generated after importing the dependency io.grpc:grpc-kotlin-stub
. This comes with build in coroutine support. I've been using the java stub the whole time.gildor
10/03/2020, 7:54 AM