Ok, I think I got it, `coroutineScope` doesn't ret...
# coroutines
d
Ok, I think I got it,
coroutineScope
doesn't return until it completes... but then, I'd need to pass the CoroutineScope in
download(scope: CoroutineScope)
? That's a bit messy... and I can't even use a receiver since it's declared on another object... (unless I use
with
... 😒)
m
Yes, that's the problem. Was just going to write it 🙂
j
Declare
CoroutineScope.download()
instead
m
You should write functions that start a coroutine like this:
fun CoroutineScope.download() =
.
👍 1
d
But I call it like this:
Copy code
client.download(url, it.sink, it.range).consumeEach { currBytes ->
						val currTotal = totalDownloaded.addAndGet(currBytes)
						i { "progress: $currTotal" }
						progress.send(DownloadProgress.Downloading(currTotal, totalExpectedPartsSize))
					}
Since
client
is the dependency where it's declared...
So I'd have to:
with(client) { download(...).consumeEach { ... } }
😛
👌 1
j
Or you could simply use
GlobalScope.produce
. I think it is okay in this case, since you use
consumeEach
, the producer will anyway be cancelled if the consumer is cancelled or failed.
d
Oh.. that's why all the ReceiveChannel operators are defined with
GlobalScope
? I guess it'll take a bit of time to get used to structured concurrency... but it's probably worth it 🙂
👍 1
with(client) { download(...).consumeEach { ... } }
gets VERY messy with Unit tests... 🙃
m
Maybe you could pass
client
as a normal parameter?
download(client, ....).consumeEach { ... } }
d
download
is defined on
client
...
Two receivers...
So the
with
just factors out the
client
receiver, allowing Kotlin to infer the CoroutineScope reciever.
This is not such a pleasant pattern for OOP programming...
The only alternative is to pass the CoroutineScope around using DI... or use GlobalScope 🙈
Quoting Vsevolod.. 'global scope is usually not recommended. Mostly, it’s red flag “I give up and just want it to work somehow somewhere”'
n
Wait, why does
Client
not implement
CoroutineScope
?
d
Because it's not my outer scope... I need the downloading to be cancelled if my outer scope (an Android IntentService) is cancelled... @nulldev
m
You could also do it the other way around by the way,
client.download(scope, ....)
. Having the scope as the receiver is just a convention.
d
True, but then passing it in the constructor is probably much cleaner, because it's not something that changes every call I make to
download
... like I said, it comes out nicer in functional programming 🙂... but I think they should have some examples in the official docs that are not functional oriented...