aaverin
06/06/2019, 11:07 AM@ExperimentalCoroutinesApi
public fun <T : Any> Deferred<T>.asSingle(context: CoroutineContext): Single<T> = GlobalScope.rxSingle(context) {
this@asSingle.await()
}
calling myDeferred.asSingle(coroutineContext)
will immediately call await()
on the deferred, which effectively starts coroutine execution.
Shouldn’t this only happen when Single will be subscribed on?aaverin
06/06/2019, 11:09 AMbezrukov
06/06/2019, 11:17 AMaaverin
06/06/2019, 11:19 AMmySingle.toObservable()
subscribe then?bezrukov
06/06/2019, 11:20 AMmySingle.toObservable().subscribe()
, mySingle.toObservable()
is just a cold observableaaverin
06/06/2019, 11:24 AMprintln("outside")
async {
println("inside")
}.asSingle(CommonPool)
I get 2 prints
inside and outsideaaverin
06/06/2019, 11:25 AMsimon.vergauwen
06/06/2019, 11:28 AMsimon.vergauwen
06/06/2019, 11:28 AMasync
runs eagerly, so the println
is printed eagerly. That behavior comes from async
and cannot be made lazy by Single
.simon.vergauwen
06/06/2019, 11:29 AMprintln("outside")
async(start = CoroutineStart.LAZY) {
println("inside")
}.asSingle(CommonPool)
This should yield your expected result.simon.vergauwen
06/06/2019, 11:30 AMDeferred
is lazy than the Single
will also be lazy. Otherwise Single
just `await`s the eagerly running Deferred
.aaverin
06/06/2019, 12:34 PMsimon.vergauwen
06/06/2019, 12:36 PMDeferred
as return types and use suspend fun
instead. Discouples the implementation of the execution strategy.aaverin
06/06/2019, 12:37 PMaaverin
06/06/2019, 12:38 PMsimon.vergauwen
06/06/2019, 12:39 PMsuspend fun
in between. You need a layer of in-direction in between.simon.vergauwen
06/06/2019, 12:41 PMimport kotlinx.coroutines.Deferred
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
object ExternalApi {
fun helloWorld(): Deferred<Unit> = GlobalScope.async {
println("Hello World!")
}
}
suspend fun indirection(): Unit =
ExternalApi.helloWorld().await()
simon.vergauwen
06/06/2019, 12:41 PMsuspend fun
should only be invoked on subscription, this will cause a new deferred to start running.simon.vergauwen
06/06/2019, 12:43 PMhelloWorld
returns a new Deferred
every-time, i.e a new network request every-time and not some cached internal values.simon.vergauwen
06/06/2019, 12:44 PMsuspend
functions instead of Deferred
.aaverin
06/06/2019, 12:45 PMfun convertToProperSingle(): Single<ExternalResponse> {
return async(start = Coroutine.LAZY) { callExternalApi() }
}.asSingle(CommonPool)
private suspend fun callExternalApi(): ExternalResponse {
return externalApi.call().await()
}
simon.vergauwen
06/06/2019, 12:46 PMsuspend fun
to Single
without Deferred
?aaverin
06/06/2019, 12:46 PMsimon.vergauwen
06/06/2019, 12:48 PMfun <A> asSingle(ctx: CoroutineContext, f: suspend () -> A): Single<A> = Single.create { emitter ->
f.startCoroutine(Continuation(ctx) { result ->
result.fold({ a -> emitter.onSuccess(a) }, { e -> emitter.onFailure(e) })
})
}
simon.vergauwen
06/06/2019, 12:48 PMemitter#xxxx
function names.simon.vergauwen
06/06/2019, 12:49 PMfun convertToProperSingle(): Single<ExternalResponse> =
asSingle(CommonPool) { externalApi.call().await() }
aaverin
06/06/2019, 12:49 PMpublic fun <T> Deferred<T>.asSingle
aaverin
06/06/2019, 12:50 PMsimon.vergauwen
06/06/2019, 12:50 PMaaverin
06/06/2019, 12:50 PMaaverin
06/06/2019, 12:50 PMsimon.vergauwen
06/06/2019, 12:50 PMZach Klippenstein (he/him) [MOD]
06/06/2019, 3:14 PMCoroutineScope.rxSingle
is already lazy, just use it directly instead of going through the asSingle
extension.Zach Klippenstein (he/him) [MOD]
06/06/2019, 3:16 PMfun convertToProperSingle(): SingleExternalResponse {
return GlobalScope.rxSingle(CommonPool) {
callExternalApi()
}
}
private suspend fun callExternalApi(): ExternalResponse {
return externalApi.call().await()
}