Retrofit2源码解析——网络调用流程(下)

Retrofit2源码解析系列

本文基于Retrofit2的2.4.0版本bash

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
复制代码

上次咱们分析到网络请求是经过OkHttpCall类来完成的,下面咱们就来分析下OkHttpCall类。微信

final class OkHttpCall<T> implements Call<T> {

    ...
    @Override
    public void enqueue(final Callback<T> callback) {
        checkNotNull(callback, "callback == null");

        okhttp3.Call call;
        Throwable failure;

        synchronized (this) {
            if (executed) throw new IllegalStateException("Already executed.");
            executed = true;

            call = rawCall;
            failure = creationFailure;
            if (call == null && failure == null) {
                try {
                    //调用createRawCall建立OkHttp3的Call
                    call = rawCall = createRawCall();
                } catch (Throwable t) {
                    throwIfFatal(t);
                    failure = creationFailure = t;
                }
            }
        }

        ...

        call.enqueue(new okhttp3.Callback() {
            @Override
            public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
                Response<T> response;
                try {
                    //解析返回的结果
                    response = parseResponse(rawResponse);
                } catch (Throwable e) {
                    callFailure(e);
                    return;
                }

                try {
                    callback.onResponse(OkHttpCall.this, response);
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }

            @Override
            public void onFailure(okhttp3.Call call, IOException e) {
                callFailure(e);
            }

            private void callFailure(Throwable e) {
                try {
                    callback.onFailure(OkHttpCall.this, e);
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        });
    }
    
    ...
}
复制代码

OkHttpCall的enqueue方法主要干了2件事,一个是建立OkHttp3的Call用于执行网络请求;另外一个是解析返回的结果并回调。下面咱们来看看建立OkHttp3的Call的过程网络

//OkHttpCall.class
private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = serviceMethod.toCall(args);
    if (call == null) {
        throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
}
复制代码

能够发现是经过serviceMethod的toCall方法来建立的app

//ServiceMethod.class
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
            contentType, hasBody, isFormEncoded, isMultipart);

    ...
    for (int p = 0; p < argumentCount; p++) {
        handlers[p].apply(requestBuilder, args[p]);
    }
    //最后调用OkHttpClient的newCall方法返回Call
    return callFactory.newCall(requestBuilder.build());
}
复制代码

ServiceMethod的toCall方法也是经过OkHttpClient的newCall方法来返回Call的。异步

在咱们经过OkHttpClient请求获得结果后,咱们还须要将返回的结果Response解析成咱们接口须要的实体类型,这就须要用到咱们在建立Retrofit时设置的ConverterFactory了,好比GsonConverterFactory。ide

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

    rawResponse = rawResponse.newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();

    ...

    ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
    try {
        //经过serviceMethod的toResponse方法解析
        T body = serviceMethod.toResponse(catchingBody);
        return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
        
        catchingBody.throwIfCaught();
        throw e;
    }
}
复制代码

OkHttpCall的parseResponse方法调用的是serviceMethod的toResponse方法来解析返回的结果。post

//ServiceMethod.class
R toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
}
复制代码

在ServiceMethod中最后调用responseConverter的convert方法来转换返回的结果。这个responseConverter和上面分析的CallAdapter的肯定过程同样,也是在ServiceMethod的build方法中,经过调用retrofit的requestBodyConverter方法遍历咱们传入的ConverterFactory,直到找到合适的。ui

//Retrofit.class
public <T> Converter<T, RequestBody> requestBodyConverter(Type type,
                                                              Annotation[] parameterAnnotations, Annotation[] methodAnnotations) {
    return nextRequestBodyConverter(null, type, parameterAnnotations, methodAnnotations);
}

public <T> Converter<T, RequestBody> nextRequestBodyConverter(
        @Nullable Converter.Factory skipPast, Type type, Annotation[] parameterAnnotations,
        Annotation[] methodAnnotations) {
    ...

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
        Converter.Factory factory = converterFactories.get(i);
        Converter<?, RequestBody> converter =
                factory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, this);
        if (converter != null) {
            //noinspection unchecked
            return (Converter<T, RequestBody>) converter;
        }
    }

    ...
}
复制代码

须要注意的是在建立Retrofit时默认添加了一个BuiltInConverters,这个是Retrofit为咱们提供一个默认的responseConverter,它主要处理的是返回类型是ResponseBody和Void的状况。this

final class BuiltInConverters extends Converter.Factory {
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        if (type == ResponseBody.class) {
            return Utils.isAnnotationPresent(annotations, Streaming.class)
                    ? StreamingResponseBodyConverter.INSTANCE
                    : BufferingResponseBodyConverter.INSTANCE;
        }
        if (type == Void.class) {
            return VoidResponseBodyConverter.INSTANCE;
        }
        return null;
    }
    ...
}
复制代码

由于咱们通常返回值类型都是具体的实体类型,因此咱们须要添加本身的responseConverter,通常也就是GsonConverterFactory了。spa

至此,网络调用的后半部分流程也清楚了:

咱们调用Call对象的enqueue方法发起异步请求时,实际上调用的是OkHttpCall对应的enqueue方法。OkHttpCall会先调用ServiceMethod类的toCall方法利用OkHttpClient的newCall方法建立OkHttp3的call对象,而后利用这个call对象执行具体的网络请求。在网络请求返回成功之后会调用ServiceMethod类的toResponse方法利用咱们设置的responseConverter将返回结果转换成咱们须要的类型,而后经过咱们设置的回调或是默认的回调方法,将结果回调回主线程,从而完成整个请求过程。

总结

Retrofit2的网络调用的整个流程咱们已经分析完了。经过此次分析,咱们能够看到Retrofit2中最主要的就是3个类:Retrofit、ServiceMethod和OkHttpCall。这三个类指责明确,相互配合共同完成整个网络调用的流程。

(1)Retrofit负责供外部初始化和定制,保存CallAdapter的列表和ResponseConverterFactory列表。

(2)ServiceMethod对应每个接口方法的信息,包括解析注解和参数等,同时它也是链接Retrofit和OkHttpCall的桥梁。ServiceMethod中保存着当前接口对应方法所须要的CallAdapter和ResponseConverter。利用CallAdapter将OkHttpCall转换成接口须要的类型,供接口调用。利用toResponse方法让OkHttpCall调用ResponseConverter解析网络请求返回的结果。

(3)OkHttpCall则是用来执行具体网络请求。Retrofit2没有直接使用OkHttp3的Call接口,而是有本身的Call接口。在OkHttpCall内部经过组合的方法持有OkHttp3的Call接口,并经过ServiceMethod的toCall方法获得OkHttp3的call来进行网络请求,减小对OkHttp3的耦合。


欢迎关注个人微信公众号,和我一块儿天天进步一点点!
复制代码

AntDream
相关文章
相关标签/搜索