I'm using an event queue based on a `Channel` like...
# coroutines
d
I'm using an event queue based on a
Channel
like this:
Copy code
val eventQueue = Channel<ApplicationInstallRequest>()

	init {
		initEventProcessor()
	}

	private fun initEventProcessor() = launch(Unconfined) {
		for (request in eventQueue) {
			processRequest(request)
		}
	}

	override fun onEvent(event: ApplicationInstallRequest) {
		eventQueue.sendBlocking(event)
	}
from an Android SyncAdapter, but even when the sync is finished, the process keeps on going (some kind of leak...), does Unconfined have it's own thread or something?
l
Android kills processes when it's out of RAM or when a non foreground, long running process consumes too much resources like CPU. So if the RAM pressure is low, it keeps the processes alive, so the apk don't need to be reloaded in RAM from storage again next time something is going on with this same app (like another sync session)
d
Right, but then all processes should be stopped...? The downloading is continuing even though the sync adapter stops and the attached service is killed.
Also, I don't think it ran out of ram, I'm not getting those in the logs at least, and I have enough Ram and no other apps running...
For some reason, I think it thinks the sync is finished because of coroutines, so it just keeps going and finishes...
But the coroutine is still running...
l
Right, but then all processes should be stopped...?
No, you misread/misunderstood my statement (which is inspired from Android docs)
I have enough Ram and no other apps running
That's why your process doesn't get killed by Android
d
It would be fine if the Service was still alive... the problem is that the service is dead, and the process keeps running...
l
Anyway, do what is right in your app, understand the lifecycle of the components you use, and make your app do only necessary work. having a parent job that you cancel in methods like
onDestroy()
is a good idea also
t would be fine if the Service was still alive... the problem is that the service is dead, and the process keeps running...
That's totally normal.
d
So I don't have to kill it on
onDestroy
?
Isn't that considered a leak?
l
The process just sits there in case the service or any other component in your app is started again, so it's not needed to load the apk from scratch back again
What do you call "kill" ?
In this:
So I don't have to kill it on
onDestroy
?
d
Meaning cancel the coroutine (and the download)
l
kill and cancel are not the same things
When your process is killed, you can rest assured everything in your app has been aborted
But when you cancel a coroutine, it can take some time to be effectively cancelled, or it can not support cancellation, and just keep on running until it reaches a point that detects cancellation or until it completes
Yes you should cancel your service related coroutines in
onDestroy()
, especially if they involve I/O or other limited resources that may drain the battery or consume power/resources needlessly when you should have stopped the work
d
The problem is that they only run after
onDestroy
, which was my problem in the first place 🤕 , so the download won't run... I think I'm doing something wrong with coroutines...
At first, I had CompletableDeferred's all over the place and it was working.. when I tried simplifying the code, and using
suspend fun
instead of all the actors and launches... I started having these problems...
l
I'm not sure what you're trying to do, but I think you're going overcomplicated, probably because there's something you didn't fully grasp. If you can tell me what you're using coroutines for in this problematic case, I can probably help you
d
I'm trying to download files in parts, as part of a bigger sync process, and a sync might be started from another service at the same time. I'm using the channel as a barrier that only one download should run at a time. (Afterwards I was planning to check for each request if that same file is already underway and check if the user cancelled download on that request...
l
@dave08 Can the user manually cancel the download, and is it tied to the same mechanism you are trying to use for cancelling when the sync adapter or the service is destroyed?
d
No, he can only cancel by running the sync again (not my code, I'm stuck with that api for now..)
l
So what you need is either a
Mutex
(from kotlinx.coroutines, which suspends instead of blocking), which you put in a top level val or in an
object
, or an
actor
. And not a big deal if sync continues after the service or sync adapter is stopped. If there's not internet, it will fail and stop by itself, and if the system really needs the resources, it will throttle or kill the process
d
But any reference to the application context won't fail? I tried actors, it gets very messy with tons of extra classes with all the different requests and responses. And completable deferreds... the new actors look much better simple smile , I hope they'll come out soon...
l
@dave08
sendBlocking
doesn't suspend but blocks while the underlying
send
is suspended (if
offer
didn't work in the first place). You shall never use
sendBlocking
from a coroutine
d
I stand corrected 🙂, in my case, that's what I needed since I'm running in a background thread in a
Service
...
d
In the same use cas, I use
offer
and it works perfectly
l
offer
has different behaviors following the type or capacity of the channel though, it's important to be sure it's right for the use case