背景:所以,我有一个相当大的项目,其中包含很多 API 函数。我正在考虑完全转向协程,但由于它们是作为 Callback
而不是 Deferred
实现的,所以我无法有效地使用它们。例如:我想异步执行 apiCallOne()
、apiCallTwo()
和 apiCallThree()
并调用 .await()
在更改 UI 之前等待最后一个请求完成。
现在项目结构如下:
最底部(或顶部)是ApiService.java
:
interface ApiService {
@GET("...")
Call<Object> getData();
...
}
然后我有一个 ClientBase.java
:
function createRequest()
是解析改造响应的主要函数。
void getUserName(String name, ApiCallback<ApiResponse<...>> callback) {
createRequest(ApiService.getData(...), new ApiCallback<ApiResponse<?>>() {
@Override
public void onResult(ServiceResponse response) {
callback.onResult(response);
}
});
}
private void createRequest(Call call, final ApiCallback<ApiResponse<?>> callback) {
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, retrofit2.Response response) {
//heavy parsing
}
// return request results wrapped into ApiResponse object
callback.onResult(new ApiResponse<>(...));
}
@Override
public void onFailure(Call call, Throwable t) {
// return request results wrapped into ApiResponse object
callback.onResult(...);
}
});
}
ApiCallback
和 ApiResponse
看起来像这样:
public interface ApiCallback<T> {
void onResult(T response);
}
public class ApiResponse<T> {
private T mResult;
private ServiceError mError;
...
}
因此,在所有这些之前,我还有 ApiClient.java
,它使用 ClientBase.createRequest()
:
public void getUserName(String name, ApiCallback<ApiResponse<..>> callback) {
ClientBase.getUserName(secret, username, new ServiceCallback<ServiceResponse<RegistrationInvite>>() {
@Override
public void onResult(ServiceResponse<RegistrationInvite> response) {
...
callback.onResult(response);
}
});
}
如您所见,这非常非常糟糕。我怎样才能至少传输部分代码以确保 ApiClient.java
函数返回 Deferred
对象? (我愿意为此创建另一个包装类)
最佳答案
所以一般来说,一个简单的方法是从挂起函数返回一个 suspendCancellableCoroutine
,然后你可以异步完成。所以在你的情况下,你可能会写这样的东西:
suspend fun getUserName(name: String): ApiResponse<...> {
return suspendCancellableCoroutine { continuation ->
createRequest(ApiService.getData(...), new ApiCallback<ApiResponse<...>>() {
@Override
public void onResult(ApiResponse<...> response) {
continuation.resume(response)
}
});
}
}
您基本上返回一个 SettableFuture
的等价物,然后在您获得成功或失败时将其标记为完成。如果您想通过异常处理来处理错误,还有 continueWithException(Throwable)
。
也就是说:
由于您使用的是 Retrofit,我建议您只添加 retrofit2-kotlin-coroutines-adapter native 为您添加此支持的依赖项。
关于android - 将回调 hell 转换为延迟对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55626871/