Retrofit 框架源码学习

Retrofit,OkHttp,Okio Square 安卓平台网络层三板斧源码学习
基于 retrofit 2.4.0-SNAPSHOT 版本 retrofit github 地址

Retrofit 是 Square 安卓平台网络层三板斧最后一个项目,Retrofit 依赖 OkHttp 。Retrofit 让 http 网络请求更加清晰。

使用方式

  1. 声明一个接口,并用接口描述 request

     public interface GitHubService {
         @GET("users/{user}/repos")
         Call<List<Repo>> listRepos(@Path("user") String user);
     }
    

    方法上面的注释表示 request 的接口名 ,方法的返回类型就是 http 请求的返回值,方法的参数就是 http 的请求参数。

  2. 创建一个 Retrofit 客户端

     Retrofit retrofit = new Retrofit.Builder()
     .baseUrl("https://api.github.com/")
     .build();
    
     GitHubService service = retrofit.create(GitHubService.class);
    

    Retrofit 创建的时候指定了 request 的接口地址,然后调用 retrofit.create 方法创建一个 GitHubService 实例。

  3. 发起网络请求

     Call<List<Repo>> repos = service.listRepos("octocat");
     repos.execute().body()
    

Retrofit 创建 Service 实例

上面的例子可以看到,retrofit.create() 方法会创建一个 GitHubService 实例,但是 GitHubService 本身是一个接口。为了了解 retrofit.create() 方法,我们先看下 Retrofit 的创建过程。

创建 Retrofit 对象。

Retrofit 和 OkHttp 一样都是使用构建者模式创建对象。先看下 Retrofit.Builder 的 build() 方法。

    public Retrofit build() {
        if (baseUrl == null) {
            throw new IllegalStateException("Base URL required.");
        }

        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null) {
            callFactory = new OkHttpClient();
        }

        Executor callbackExecutor = this.callbackExecutor;
        if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
        }

        // Make a defensive copy of the adapters and add the default Call adapter.
        List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
        adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

        // Make a defensive copy of the converters.
        List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

        return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
                callbackExecutor, validateEagerly);
    }

创建 Retrofit 的时候需要传递一下几个参数

1. callFactory 用来创建一个实现了 okhttp3.Call.Factory 的对象,如果没有设置,默认为 OkHttpClient。
2. baseUrl 网络接口的地址。
3. converterFactories 用来把服务器返回的数据转换为对象。
4. adapterFactories 用来发起网络请求。
5. callbackExecutor 是一个调度器,用来接收返回的数据,在 Android 上默认是封装了 handler 的 MainThreadExecutor
6. validateEagerly  是一个开关,如果为 true 会缓存创建的 ServiceMethod 。

retrofit.create()

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
        eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[]{service},
            new InvocationHandler() {
                private final Platform platform = Platform.get();

                @Override
                public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                        throws Throwable {
                    // If the method is a method from Object then defer to normal invocation.
                    if (method.getDeclaringClass() == Object.class) {
                        return method.invoke(this, args);
                    }
                    if (platform.isDefaultMethod(method)) {
                        return platform.invokeDefaultMethod(method, service, proxy, args);
                    }
                    ServiceMethod<Object, Object> serviceMethod =
                            (ServiceMethod<Object, Object>) loadServiceMethod(method);
                    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                    return serviceMethod.callAdapter.adapt(okHttpCall);
                }
            });
}

这里用到了一个公共技术点之 Java 动态代理,create 方法传入一个 Class ,这个 Class 对象就是上文的 GitHubService 的 Class 。

GitHubService 的方法是由 InvocationHandler 代理实现的,重点看三行代码

……
ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
第一行 loadServiceMethod(method)
ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
        result = serviceMethodCache.get(method);
        if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
        }
    }
    return result;
}

这里创建了一个 ServiceMethod 对象。

第二行 new OkHttpCall<>(serviceMethod, args)
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
}

创建了一个 OkHttpCall ,serviceMethod 和 args 是 OkHttpCall 的成员函数。

所以,

第三行 serviceMethod.callAdapter.adapt(okHttpCall)

这里需要明白 serviceMethod.callAdapter 是怎么来的

1. 在 ServiceMethod.Builder.build() 中调用 createCallAdapter()
2. 在 createCallAdapter() 中会找到 
   (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations)
3. 在 callAdapter() 中调用 nextCallAdapter
4. nextCallAdapter 会遍历 adapterFactories 返回一个 CallAdapter。

这里再回头看下 adapterFactories Retrofit.Builder.build() 方法中

List<CallAdapter.Factory> adapterFactories = 
    new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

而在 Retrofit.nextCallAdapter() 中

int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
   CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
        return adapter;
    }
}

如果没有设置 AdapterFactory 将会使用一个默认的 AdapterFactory

CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor != null) {
        return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
}

所以如果我们设置了一个 RxJavaCallAdapterFactory,就会返回 RxJavaCallAdapterFactory。

retrofit_01.png

发起网络请求

通过 retrofit.create() 我们可以知道,retrofit.create() 返回的是一个代理对象InvocationHandler ,那么在执行

Call<List<Repo>> repos = service.listRepos("octocat");

方法时,调用的实际上是 callAdapter.adapt(okHttpCall),以 DefaultCallAdapterFactory 为例

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

    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
        @Override
        public Type responseType() {
            return responseType;
        }

        @Override
        public Call<Object> adapt(Call<Object> call) {
            return call;
        }
    };
}

结合 retrofit.create() 方法可以得知这里返回的是一个 OkHttpCall 对象。

接下来使用 OkHttpCall.execute() 或者异步执行 enqueue(Callback<T> callback)

这两种方式都会调用 createRawCall() 创建一个 okhttp3.Call

private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}

此处的 serviceMethod.callFactory 就是 retrofit.create() 中创建的 OkHttpClient()
后面的内容都是由 Okhttp 模块接管,进行网络请求,参考okHttp 框架源码学习

然后调用 parseResponse(call.execute())

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();

    ……
    省略一些 http 返回值处理逻辑
    ……
    try {
        T body = serviceMethod.toResponse(catchingBody);
        return Response.success(body, rawResponse);
    } ……
}

okHttp 请求网络的返回数据,会交给 serviceMethod.toResponse

R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
}

在 ServiceMethod.Builder.build() 方法中可以找到 responseConverter 是通过 createResponseConverter() 方法的返回对象。

createResponseConverter() 只是报包裹了 retrofit.responseBodyConverter(responseType, annotations) 方法。

retrofit.responseBodyConverter() 继续跟踪下去会得知,返回的是 converterFactories 数组的第 0 个对象,也就是内置的 BuiltInConverters.responseBodyConverter() 方法返回的 BufferingResponseBodyConverter

static final class BufferingResponseBodyConverter
        implements Converter<ResponseBody, ResponseBody> {
    static final BufferingResponseBodyConverter INSTANCE = new BufferingResponseBodyConverter();

    @Override
    public ResponseBody convert(ResponseBody value) throws IOException {
        try {
            // Buffer the entire body to avoid future I/O.
            return Utils.buffer(value);
        } finally {
            value.close();
        }
    }
}

再看一下 Utils.buffer(value)

static ResponseBody buffer(final ResponseBody body) throws IOException {
    Buffer buffer = new Buffer();
    body.source().readAll(buffer);
    return ResponseBody.create(body.contentType(), body.contentLength(), buffer);
}

最终会返回一个重新封装的 Okhttp 框架的 ResponseBody 对象。

retrofit_02.png

参考资料

Retrofit 官方文档

retrofit github 地址

拆轮子系列:拆 Retrofit

Android:手把手带你深入剖析 Retrofit 2.0 源码

Retrofit分析-经典设计模式案例

Retrofit分析-漂亮的解耦套路

推荐阅读更多精彩内容