返回

Retrofit 深入剖析:自定义 CallAdapter,优雅处理错误信息

Android

Android Retrofit 源码系列(二)~ 自定义 CallAdapter

在上一篇 Retrofit 源码分析文章中,我们深入探讨了 CallAdapter 在 Retrofit 中的关键作用。今天,我们将更进一步,学习如何自定义 CallAdapter,从而优雅地处理错误信息。通过剖析源码,我们将揭开自定义 CallAdapter 背后的秘密。

自定义 CallAdapter 的必要性

默认情况下,Retrofit 会将网络请求的结果以 Call 对象的形式返回。Call 对象提供了丰富的 API,用于管理网络请求的生命周期。然而,当发生错误时,Retrofit 并不会对错误信息进行统一的封装,这给后续的错误处理带来了不便。

自定义 CallAdapter 可以解决这个问题。通过创建一个自定义的 CallAdapter,我们可以对错误信息进行统一的封装和处理,从而简化代码并提高可维护性。

创建自定义 CallAdapter

让我们从一个简单的示例开始,自定义一个 CallAdapter 来封装常见的网络错误,例如超时和连接失败。

public class ErrorHandlingCallAdapterFactory extends CallAdapter.Factory {

    @Override
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        }
        return new ErrorHandlingCallAdapter<>(retrofit);
    }

    private static class ErrorHandlingCallAdapter<R> implements CallAdapter<R, Call<R>> {

        private final Retrofit retrofit;

        public ErrorHandlingCallAdapter(Retrofit retrofit) {
            this.retrofit = retrofit;
        }

        @Override
        public Type responseType() {
            return getRawType(getParameterUpperBound(0, getCallAdapterMethod().getGenericReturnType()));
        }

        @Override
        public Call<R> adapt(Call<R> call) {
            return new ErrorHandlingCall<>(call, retrofit);
        }
    }
}

工作原理:

  1. ErrorHandlingCallAdapter 类实现了 CallAdapter.Factory 接口,用于创建自定义的 CallAdapter。
  2. get() 方法检查返回类型是否为 Call。如果不是,则返回 null
  3. ErrorHandlingCallAdapter 的内部类实现了 CallAdapter 接口,并负责实际的错误处理逻辑。
  4. adapt() 方法将原始的 Call 对象包装在一个 ErrorHandlingCall 对象中,该对象负责在错误发生时进行封装。

自定义 CallAdapter 的执行流程

让我们一步步分析 ErrorHandlingCall 的执行流程:

private static class ErrorHandlingCall<R> implements Call<R> {

    private final Call<R> delegate;
    private final Retrofit retrofit;

    public ErrorHandlingCall(Call<R> delegate, Retrofit retrofit) {
        this.delegate = delegate;
        this.retrofit = retrofit;
    }

    @Override
    public Response<R> execute() throws IOException {
        try {
            return delegate.execute();
        } catch (Throwable throwable) {
            throw RetrofitException.convertException(throwable);
        }
    }

    @Override
    public void enqueue(Callback<R> callback) {
        delegate.enqueue(new ErrorHandlingCallback<>(callback, retrofit));
    }

    @Override
    public boolean isExecuted() {
        return delegate.isExecuted();
    }

    @Override
    public void cancel() {
        delegate.cancel();
    }

    @Override
    public boolean isCanceled() {
        return delegate.isCanceled();
    }
}

工作原理:

  1. ErrorHandlingCall 的构造函数接收原始的 Call 对象和 Retrofit 实例。
  2. execute() 方法在发生错误时将其包装为 RetrofitException
  3. enqueue() 方法将回调包装在一个 ErrorHandlingCallback 对象中,该对象负责将封装后的错误传递给原始回调。
  4. 其他方法将委托给原始的 Call 对象。

集成到 Retrofit

要集成我们的自定义 CallAdapter,我们只需在 Retrofit.Builder 中使用 addCallAdapterFactory() 方法即可。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://example.com/")
    .addCallAdapterFactory(new ErrorHandlingCallAdapterFactory())
    .build();

总结

通过自定义 CallAdapter,我们实现了对 Retrofit 错误信息的统一封装和处理。这不仅提高了代码的可维护性,而且使错误处理更加健壮和优雅。通过分析源码,我们深入了解了自定义 CallAdapter 的执行流程,为我们提供了强大且可定制的工具,用于管理 Retrofit 网络请求。