android - 将回调 hell 转换为延迟对象

标签 android kotlin coroutine kotlin-coroutines

背景:所以,我有一个相当大的项目,其中包含很多 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(...);
        }
    });
}

ApiCallbackApiResponse 看起来像这样:

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/

相关文章:

kotlin - Kotlin 协程中的 "+"?

android - Kotlin 协程处理错误和实现

android - 在 Android 注解中使用 @Rest 进行多部分发布

android - edittext.settext() 将键盘类型更改为默认值 [从 ?123 到 ABC]

android - 有什么方法可以使用注释 @Binds 而不是 @Provides 和需要参数的返回类型

intellij-idea - java.lang.NoClassDefFoundError:kotlin/jvm/internal/Intrinsics

android - fill_parent 和 wrap_content 有什么区别?

Android:如何使用选择器?

java - 为什么 Kotlin 没有显式类型?

c - 交换到 ucontext_t 的 uc_link 时发生 swapcontext 段错误