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>.asSingleaaverin
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()
}