美文网首页Android开发经验谈Android开发Android开发
Retrofit2源码解析——网络调用流程(下)

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

作者: AntDream | 来源:发表于2018-08-18 21:24 被阅读21次

    Retrofit2源码解析系列

    本文基于Retrofit2的2.4.0版本

    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方法来创建的

    //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。

    //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方法来解析返回的结果。

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

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

    //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的情况。

    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了。

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

    我们调用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

    相关文章

      网友评论

        本文标题:Retrofit2源码解析——网络调用流程(下)

        本文链接:https://www.haomeiwen.com/subject/mfhqiftx.html