I'm trying to dive into coroutines world, trying to make some network work in Service
(in fact LifecycleService
). after starting it I'm calling below method
private fun runConnectionCoroutine() {
job = lifecycleScope.launch(Dispatchers.IO) {
try {
doSomeNetworking()
if (!isActive) return@launch
publishResult()
}catch (e: CancellationException){
}
}
}
doSomeNetworking()
may take too much time, so user should be able to dimiss this task and Service
. I'm calling then job?.cancel()
and then stopSelf()
. As expected coroutine doesn't stop immediatelly (thats why if (!isActive) return@launch
line is there), but Service
does and leakcanary detects: CoroutineScheduler$Worker
keeps reference to this Service
so the question is: how to properly stop Service
during networking coroutine?
isActive
check does not make too much of a difference. What we need to do is to check forisActive
during the long running task. And do it regularly, e.g. each 100ms. – SirrahdoSomeNetworking()
. If you are performing blocking I/O reads then usually there are some alternatives to do it in a non-blocking way or at least to specify a timeout. This way you can read data and at the same time verifyisActive
status frequently. You can also switch I/O API/library to one that is fully non-blocking, e.g.:okio
orNIO
, etc. – SirrahdoSomeNetworking()
in my case is using GRPC and I've configured some timeouts, but still there is a case, when networking starts at some point and after 10 msService
gets killed for some not-networking-related reason (e.g. user desire). I'm cancelingjob
inonDestroy
, but this coroutine still works and hold reference to killedService
, so leak... anyway, dzięki za komentarz – Noland