https://kotlinlang.org logo
Title
d

dave08

10/29/2018, 12:34 PM
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

marstran

10/29/2018, 12:34 PM
Yes, that's the problem. Was just going to write it 🙂
j

Jonathan

10/29/2018, 12:34 PM
Declare
CoroutineScope.download()
instead
m

marstran

10/29/2018, 12:34 PM
You should write functions that start a coroutine like this:
fun CoroutineScope.download() =
.
👍 1
d

dave08

10/29/2018, 12:36 PM
But I call it like this:
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 { ... } }
😛
:yes: 1
j

Jonathan

10/29/2018, 12:38 PM
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

dave08

10/29/2018, 12:41 PM
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

marstran

10/29/2018, 2:07 PM
Maybe you could pass
client
as a normal parameter?
download(client, ....).consumeEach { ... } }
d

dave08

10/29/2018, 2:08 PM
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

nulldev

10/29/2018, 3:46 PM
Wait, why does
Client
not implement
CoroutineScope
?
d

dave08

10/29/2018, 3:48 PM
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

marstran

10/29/2018, 5:19 PM
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

dave08

10/29/2018, 5:22 PM
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...