修改延迟结果
Modify the Deferred result
给定一个 API(由 Retrofit) that returns a model. I wrap an old fashioned 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
和return里面的对象Deferred
:
fun getDummyAge(): Deferred<Int> {
// return getDummy().age
}
我是协程的新手,所以这可能不是这里的工作方式。假设我是一个 RxJava 粉丝,我会像这样实现这个案例:
fun getDummy(): Single<Dummy> = api.getDummy().toSingle()
fun getDummyAge(): Single<Int> = getDummy().map { it.age }
那么我应该尝试从 getDummyAge
函数中 return 一个 Deferred
吗?或者最好尽可能声明一个 suspended fun
并在我的所有 api 方法上调用 deferred.await()
?
如果您遵循 async 风格 编程,即编写 return Deferred<T>
的函数,那么您可以定义 async 函数 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
return 是 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))
}
}
})
}
如果您想详细了解异步函数和挂起函数之间的风格差异,那么我建议您观看 Introduction to Coroutines from KotlinConf 2017. If you prefer a short read, then this section from the design document 也提供了一些见解。
给定一个 API(由 Retrofit) that returns a model. I wrap an old fashioned 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
和return里面的对象Deferred
:
fun getDummyAge(): Deferred<Int> {
// return getDummy().age
}
我是协程的新手,所以这可能不是这里的工作方式。假设我是一个 RxJava 粉丝,我会像这样实现这个案例:
fun getDummy(): Single<Dummy> = api.getDummy().toSingle()
fun getDummyAge(): Single<Int> = getDummy().map { it.age }
那么我应该尝试从 getDummyAge
函数中 return 一个 Deferred
吗?或者最好尽可能声明一个 suspended fun
并在我的所有 api 方法上调用 deferred.await()
?
如果您遵循 async 风格 编程,即编写 return Deferred<T>
的函数,那么您可以定义 async 函数 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
return 是 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))
}
}
})
}
如果您想详细了解异步函数和挂起函数之间的风格差异,那么我建议您观看 Introduction to Coroutines from KotlinConf 2017. If you prefer a short read, then this section from the design document 也提供了一些见解。