给定一个返回模型的API(由Retrofit实现)。我使用扩展函数将旧的Call包装到Deferred
中:
fun <T> Call<T>.toDeferred(): Deferred<T> {
val deferred = CompletableDeferred<T>()
// cancel request as well
deferred.invokeOnCompletion {
if (deferred.isCancelled) {
cancel()
}
}
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>?, t: Throwable) {
deferred.completeExceptionally(t)
}
override fun onResponse(call: Call<T>?, response: Response<T>) {
if (response.isSuccessful) {
deferred.complete(response.body()!!)
} else {
deferred.completeExceptionally(HttpException(response))
}
}
})
return deferred
}
现在我可以得到这样的模型:
data class Dummy(val name: String, val age: Int)
fun getDummy(): Deferred<Dummy> = api.getDummy().toDeferred()
但我如何修改 Deferred
内的对象并返回Deferred
:
fun getDummyAge(): Deferred<Int> {
// return getDummy().age
}
我是协同程序的新手所以可能这不是这里的事情如何完成的。假设我是RxJava粉丝我会实现这种情况,如:
fun getDummy(): Single<Dummy> = api.getDummy().toSingle()
fun getDummyAge(): Single<Int> = getDummy().map { it.age }
我应该尝试从Deferred
函数返回getDummyAge
吗?或者可能最好尽可能地声明suspended fun
,并在我的所有api方法上调用deferred.await()
?
答案 0 :(得分:21)
如果您按照 async style 进行编程,即编写返回Deferred<T>
的函数,那么您可以像这样定义 async function getDummyAge
:
fun getDummyAge(): Deferred<Int> = async { getDummy().await().age }
但是,这种编程风格一般不建议在Kotlin中使用。惯用的Kotlin方法是使用以下签名定义暂停扩展函数 Call<T>.await()
:
suspend fun <T> Call<T>.await(): T = ... // more on it later
并使用它来编写暂停功能 getDummy
,直接返回Dummy
类型的结果,而不将其包装为延迟:
suspend fun getDummy(): Dummy = api.getDummy().await()
在这种情况下,您可以轻松编写暂停功能 getDummyAge
:
suspend fun getDummyAge(): Int = getDummy().age
对于Retrofit调用,您可以实现await
扩展名,如下所示:
suspend fun <T> Call<T>.await(): T = suspendCancellableCoroutine { cont ->
cont.invokeOnCompletion { cancel() }
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>?, t: Throwable) {
cont.resumeWithException(t)
}
override fun onResponse(call: Call<T>?, response: Response<T>) {
if (response.isSuccessful) {
cont.resume(response.body()!!)
} else {
cont.resumeWithException(HttpException(response))
}
}
})
}
如果您想进一步了解异步和暂停功能之间的风格差异,那么我建议您从KotlinConf 2017中观看Introduction to Coroutines。如果您更喜欢简短阅读,那么{{3}也提供了一些见解。