【Retrofit】Retrofit原理解析之原理篇

学而不思则罔,思而不学则殆


Retrofit系列文章

【Retrofit】Retrofit原理解析之使用篇
【Retrofit】Retrofit原理解析之原理篇
【Retrofit】Retrofit原理解析之注解详解篇
【Retrofit】Retrofit原理解析之设计模式总结篇

引言

在上一篇文章中,分享讲了Retrofit框架的常见使用范例,本篇分享来说一下Retrofit的的原理

整体流程

在这里插入图片描述
整体流程

  1. 新建Retrofit实例,通过构建者模式设置一些参数工厂(用来数据封装+数据解析)
  2. 调用Retrofit.create(),方法拿到自定义服务的实例
  3. 调用服务的具体方法,动态代理中根据Method生成不同的ServiceMethod<?>,并缓存起来,这一步中间逻辑比较多,可以先简单知道中间是通过注解拿到具体的网络请求基本信息,由于后续生成Request做准备。包括:GET,POST,PATH,BODY,等等
  4. 调用ServiceMethod.invoke方法,入参就是调用时的参数,生成OkHttpCall对象,此时的OkHttpCall对象已经获取了全部的网络请求基本参数
  5. 调用的OkHttpCall的enqueue/execute发起网络请求。内部显示根据之前设置的参数生成Request,然后生成okhttp3.Call对象实例
  6. okhttp3.Call对象实例后,才是真正的发起网络请求
  7. OkHttp数据返回后,OkHttpCall中数据解析后返回给调用方

一.简单范例

简单发送一个GET请求

1.1.定义服务

在上一篇分享中,定义了服务BlogService,提供了一个Get请求方法

public interface BlogService {
    @GET("retrofit/all.do")
    Call<Blog> getAll();
}

定义了一个服务,只提供了一个简单的GET方法。

1.2.构建Retrofit

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(HttpUrl.get("http://localhost:3434/"))
                .addConverterFactory(Utils.FACTORY)
                .build();

通过构建者模式构建了一个简单的Retrofit对象,其中BaseUrl = 【http://localhost:3434/】,BaseUrl + relativeUrl = 最终的Url ,也就是
【http://localhost:3434/】+【retrofit/all.do】= 【http://localhost:3434/retrofit/all.do】

1.3.添加转换器工厂

可以看到这里添加了ConverterFactory,该工厂的主要作用是用来生成具体的转换器,比如该例子中需要:
【ResponseBody】—》【Blog】
那么就需要一个转换器把ResponseBody对象转换为 Blog对象。理论上根据不同的业务我们需要定于不同的转换器工厂生成不同的装换器

public class Utils {
    static final Converter.Factory FACTORY =
            new Converter.Factory() {
                @Override
                public @Nullable
                Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
                    if (type == Blog.class) return new DataAdapter();
                    return null;
                }
                
                @Override
                public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
                    System.out.println("type:" + type + " " + Blog.class);
                    System.out.println("type:" + type + " " + Blog.class);
                    if (type == Blog.class) {
                        return new RequestBodyAdapter();
                    }
                    return null;
                }
            };

    static final class RequestBodyAdapter implements Converter<Blog, RequestBody> {
        @Override
        public RequestBody convert(Blog blog) throws IOException {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                System.out.println(stackTraceElement);
            }
            return RequestBody.create(null, blog.toString());
        }
    }


    static final class DataAdapter implements Converter<ResponseBody, Blog> {

        @Override
        public Blog convert(ResponseBody responseBody) throws IOException {
            String body = responseBody.string();
            // FIXME: 2020/11/16 数据处理
            return new Blog(body);
        }
    }}

FACTORY 主要有五个方法,这里我们只关注其中两个方法。

方法返回值说明
responseBodyConverterConverter<ResponseBody, ?>理解为ResponseBody转换器,主要是把ResponseBody对象转换成想要的对象
requestBodyConverterConverter<?, RequestBody>RequestBody转换器,主要是把指定的对象转换成RequestBody,用于网络请求

他们生产的对象都是Converter,该接口的主要功能是实现转换 F --> T

public interface Converter<F, T> {
  @Nullable
  T convert(F value) throws IOException;
}

1.4.获取Call<?>,并发起网络请求

        try {
            //获取服务实例
            BlogService blogService = retrofit.create(BlogService.class);
            //获取Call
            Call<Blog> call = blogService.getAll();
            //发起同步请求
            Response<Blog> response = call.execute();
            Blog blog = response.body();
            System.out.println(blog);
        } catch (IOException e) {
            e.printStackTrace();
        }

发起同步请求,异步请求是一样,主要是通过接口返回。发起网络请求后,内部通过OkHttp发起请求后,收到ResponseBody,在通过Converter<ResponseBody, ?> 转换器把内容转换为我们需要的类型对象。

请求结果:

//服务端
GET http://localhost:3434/retrofit/all.do?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

//客户端
Blog{body='{"code":200,"msg":"OK","des":"all.do","data":[{"id":1,"date":"2020-11-15 10:39:13","author":"fish1","title":"retrofit1","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test1"},{"id":2,"date":"2020-11-15 10:39:13","author":"fish2","title":"retrofit2","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test2"},{"id":3,"date":"2020-11-15 10:39:13","author":"fish3","title":"retrofit3","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test3"},{"id":4,"date":"2020-11-15 10:39:13","author":"fish4","title":"retrofit4","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test4"},{"id":5,"date":"2020-11-15 10:39:13","author":"fish5","title":"retrofit5","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test5"},{"id":6,"date":"2020-11-15 10:39:13","author":"fish6","title":"retrofit6","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test6"},{"id":7,"date":"2020-11-15 10:39:13","author":"fish7","title":"retrofit7","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test7"},{"id":8,"date":"2020-11-15 10:39:13","author":"fish8","title":"retrofit8","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test8"},{"id":9,"date":"2020-11-15 10:39:13","author":"fish9","title":"retrofit9","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test9"},{"id":10,"date":"2020-11-15 10:39:13","author":"fish10","title":"retrofit10","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test10"}]}'}

这样Retrofit简单的网络请求的结束了。整个过程,我们使用很简单,定义服务,在通过Retrofit构建服务实例,在通过构建的服务实例去访问网络(通过和异步都可以),接下来我们分析一下整个过程中框架帮我们做了什么事?
只有当我门真正了解内部原理,才能更好地使用这个框架。

二.构建ServiceMethod<?>

当我们调用create方法,内部通过动态代理返回服务的实例对象。

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

              @Override
              public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
                  throws Throwable {
                // If the method is a method from Object then defer to normal invocation.
                //处理Object的方法
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                //处理定义的服务方法
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

当我们调用服务端方法的时候,走到invoke方法。

2.1.双check模式构建ServiceMethod

  ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

这段代码就是类似单例模式的双check模式,用来生成解析ServiceMethod,保存到serviceMethodCache内存中,只是第一次需要解析Method,以后的调用可以直接使用。

2.2解析Method

//ServiceMethod.java
abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    //1.生成RequestFactory 
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    //2.返回值正确性判断
    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(
          method,
          "Method return type must not include a type variable or wildcard: %s",
          returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }
    //3.生成ServiceMethod
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

parseAnnotations解析注解。其中ServiceMethod是一个抽象类,子类需要实现invoke方法。
该方法主要分为三步。

  1. 解析生成RequestFactory
  2. 返回值正确性判断
  3. 生成ServiceMethod

其中第一步和第三部是重点,第二步返回值正确性判断,可以看出定义的服务方法返回值不能是Void.class类型和方法返回类型不能包含类型变量或通配符。

ServiceMethod的类图结构如下:
在这里插入图片描述

2.2.1 构建RequestFactory
//RequestFactory.java
final class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
  ...
}

RequestFactory 实例对象的生成主要是通过Builder模式,看看Builder 类。

  static final class Builder {
    ...
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    RequestFactory build() {
      //1.解析方法注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
       
      //2.解析参数
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }
      //3.返回RequestFactory实例
      return new RequestFactory(this);
    }
}

流程很清晰

  1. 解析方法的 注解 - 主要用什么方法请求网络。比如GET,POST等等
  2. 解析方法的每个参数 - 很重要,负责网络的请求的数据(包括)
  3. 生成RequestFactory实例对象
2.2.1.1解析方法的的每个注解

服务方法可以有多个注解。比如:

public interface BlogService {
    @GET("retrofit/all.do")
    Call<Blog> getAll();
    
    @POST("retrofit/login")
    @FormUrlEncoded
    Call<Blog> login(@Field("username") String username, @Field("password") String password, @Field("tag") String tag);
}

其中getAll方法只有一个注解@GET, login方法有两个注解@POST和@FormUrlEncoded

    private void parseMethodAnnotation(Annotation annotation) {
      if (annotation instanceof DELETE) {
        parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
      } else if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      } else if (annotation instanceof HEAD) {
        parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
      } else if (annotation instanceof PATCH) {
        parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
      } else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      } else if (annotation instanceof PUT) {
        parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
      } else if (annotation instanceof OPTIONS) {
        parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
      } else if (annotation instanceof HTTP) {
        HTTP http = (HTTP) annotation;
        parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
      } else if (annotation instanceof retrofit2.http.Headers) {
        String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
        if (headersToParse.length == 0) {
          throw methodError(method, "@Headers annotation is empty.");
        }
        headers = parseHeaders(headersToParse);
      } else if (annotation instanceof Multipart) {
        if (isFormEncoded) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isMultipart = true;
      } else if (annotation instanceof FormUrlEncoded) {
        if (isMultipart) {
          throw methodError(method, "Only one encoding annotation is allowed.");
        }
        isFormEncoded = true;
      }
    }
    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      if (this.httpMethod != null) {
        throw methodError(
            method,
            "Only one HTTP method is allowed. Found: %s and %s.",
            this.httpMethod,
            httpMethod);
      }
      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // Get the relative URL path and existing query string, if present.
      int question = value.indexOf('?');
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        if (queryParamMatcher.find()) {
          throw methodError(
              method,
              "URL query string \"%s\" must not have replace block. "
                  + "For dynamic query parameters use @Query.",
              queryParams);
        }
      }

      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

结合这两个方法,主要is-else判断。
其中PATCH,POST,PUT默认是有Body,当实际上没有的时候会创建一个空Body

  //RequestBuilder.java
  Request.Builder get() {
    ...
    RequestBody body = this.body;
    if (body == null) {
      // Try to pull from one of the builders.
      if (formBuilder != null) {
        body = formBuilder.build();
      } else if (multipartBuilder != null) {
        body = multipartBuilder.build();
      } else if (hasBody) {
        // Body is absent, make an empty body.
        body = RequestBody.create(null, new byte[0]);
      }
    }
  }

还有一些规则,比如Multipart和FormUrlEncoded不能同时存在。
比如:

    @Multipart
    @POST("retrofit/register")
    @FormUrlEncoded
    Call<Blog> registerUser(@Part MultipartBody.Part part, @Part("username") RequestBody username, @Part("password") RequestBody password);

//会抛出异常
Exception in thread "main" java.lang.IllegalArgumentException: Only one encoding annotation is allowed.
    for method BlogService.registerUser
	at retrofit2.Utils.methodError(Utils.java:54)
	at retrofit2.Utils.methodError(Utils.java:43)
	at retrofit2.RequestFactory$Builder.parseMethodAnnotation(RequestFactory.java:256)
	at retrofit2.RequestFactory$Builder.build(RequestFactory.java:181)
	at retrofit2.RequestFactory.parseAnnotations(RequestFactory.java:67)
	at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:26)
	at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:202)
	at retrofit2.Retrofit$1.invoke(Retrofit.java:160)
	at com.sun.proxy.$Proxy0.registerUser(Unknown Source)
	at com.example.test.MultipartTest.main(MultipartTest.java:32)
2.2.1.2解析方法的每个参数的注解

接下来是解析每个参数,这也是非常重要的点。
每个参数是可能存在多个注解的。所以这里是for循环处理参数的每个注解。

    private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
      ParameterHandler<?> result = null;
      if (annotations != null) {
        for (Annotation annotation : annotations) {
          //解析参数的每个注解
          ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);

          if (annotationAction == null) {
            continue;
          }

          if (result != null) {
            throw parameterError(
                method, p, "Multiple Retrofit annotations found, only one allowed.");
          }

          result = annotationAction;
        }
      }
      ...
      return result;
    }

parseParameterAnnotation这个方法很长,有400多行,主要就是针对每个注解判断,然后返回不同的ParameterHandler实例对象。

    @Nullable
    private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
      if (annotation instanceof Url) {
          ...
          return new ParameterHandler.RelativeUrl(method, p);
      } else if (annotation instanceof Path) {
        ...
        Converter<?, String> converter = retrofit.stringConverter(type, annotations);
        return new ParameterHandler.Path<>(method, p, name, converter, path.encoded());
      } else if (annotation instanceof Query) {
          ...
          return new ParameterHandler.Query<>(name, converter, encoded);
      } else if (annotation instanceof QueryName) {
          ...
          return new ParameterHandler.QueryName<>(converter, encoded);
      } else if (annotation instanceof QueryMap) {
        ...
        return new ParameterHandler.QueryMap<>(
            method, p, valueConverter, ((QueryMap) annotation).encoded());
      } else if (annotation instanceof Header) {
          ...
          Converter<?, String> converter = retrofit.stringConverter(iterableType, annotations);
          return new ParameterHandler.Header<>(name, converter).iterable();
      } else if (annotation instanceof HeaderMap) {
        ...
        return new ParameterHandler.HeaderMap<>(method, p, valueConverter);
      } else if (annotation instanceof Field) {
          ...
          return new ParameterHandler.Field<>(name, converter, encoded);      
      } else if (annotation instanceof FieldMap) {
        ...
        return new ParameterHandler.FieldMap<>(
            method, p, valueConverter, ((FieldMap) annotation).encoded());
      } else if (annotation instanceof Part) {
            ...
            return new ParameterHandler.Part<>(method, p, headers, converter);
      } else if (annotation instanceof PartMap) {
        ...
        PartMap partMap = (PartMap) annotation;
        return new ParameterHandler.PartMap<>(method, p, valueConverter, partMap.encoding());
      } else if (annotation instanceof Body) {
        ...
        return new ParameterHandler.Body<>(method, p, converter);
      } else if (annotation instanceof Tag) {
        ...
        return new ParameterHandler.Tag<>(tagType);
      }

      return null; // Not a Retrofit annotation.
    }

该方法真的很长,我们只是关注主要逻辑,每个注解都会返回一个对应的ParameterHandler实例对象,为后面构建网络请求的Request对象提供帮助。
该方法整体是采用了工厂模式+策略模式。根据注解类型返回对应的实例对象,每个不同的ParameterHandler子类对应不同的算法实现。
在这里插入图片描述

2.2.2 构建ServiceMethod
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    ...
    //1.根据条件生成CallAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    ...
    //2.根据条件生成Converter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    //3.根据环境生成具体的HttpServiceMethod
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForResponse<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>)
          new SuspendForBody<>(
              requestFactory,
              callFactory,
              responseConverter,
              (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
              continuationBodyNullable);
    }
  }

该方法主要分为三步:

2.2.2.1生成CallAdapter

第一步:生成CallAdapter,或者说是Call适配器。可能不好理解,举个例子:在本文的例子中我们返回的是Call<?>类型的结果,跟RxJava相结合我们可以返回Observable<?>。想要返回什么类型的,就是需要CallAdapter来处理,根据我们在构建Rettofit的时候传入不同的CallAdapterFactory。


该框架中默认实现了不同返回类型的Factory,当然也可以根据业务需要自定义。如图,是框架默认实现的Factory,默认是DefaultCallAdapterFactory,还有跟RxJava相结合的,有RxJavaCallAdapterFactory,RxJava2CallAdapterFactory和RxJava3CallAdapterFactory。
在这里插入图片描述

2.2.2.2生成Converter

第二步。根据返回的实例泛型 Converter<ResponseBody, ResponseT>,可以猜出来,返回的是把ResponseBody对象转换成我们想要的类型的转换器。当然框架默认也实现了很多转换器,如图:
在这里插入图片描述

比如常见的Json转换器GsonResponseBodyConverter,String转换器ToStringConverter等等。还有一些是结合Java8特性的lambda表达式返回值。其他的转换器感兴趣小伙伴的可以查看源码。

final class StringConverterFactory extends Converter.Factory {
  @Override
  public Converter<ResponseBody, String> responseBodyConverter(
      Type type, Annotation[] annotations, Retrofit retrofit) {
    return ResponseBody::string;
  }

  @Override
  public Converter<String, RequestBody> requestBodyConverter(
      Type type,
      Annotation[] parameterAnnotations,
      Annotation[] methodAnnotations,
      Retrofit retrofit) {
    return value -> RequestBody.create(MediaType.get("text/plain"), value);
  }
}
2.2.2.3 生成HttpServiceMethod

第三步就是返回具体的HttpServiceMethod。这里其实主要是根据Kotlin语言特性,返回不同的结果。由于对Kotlin还不是很熟习,这里就不展开了。懂得读者可以说一下。

三.构建Call<?>

该逻辑就是根据前面解析的结果HttpServiceMethod,调用invoke方法。返回OkHttpCall<?>对象或者OkHttpCall<?>对象的封装对象。默认是返回OkHttpCall<?>,封装对象最终也是调用OkHttpCall的相关方法。

  //HttpServiceMethod.java
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  ...
}

四.发起同步或异步请求

//发起同步请求
Response<Blog> response = call.execute();
  @Override
  public Response<T> execute() throws IOException {
    okhttp3.Call call;

    synchronized (this) {
      if (executed) throw new IllegalStateException("Already executed.");
      executed = true;
      //1.构建okhttp3.Call
      call = getRawCall();
    }

    if (canceled) {
      call.cancel();
    }
    //2.发起同步请求+数据解析
    return parseResponse(call.execute());
  }

该方法主要分为两步:

  1. 构建okhttp3.Call对象
  2. 发起同步请求+数据解析处理

这里可以看出框架的请求网络是通过OkHttp来处理的,Retrofit只是穿了一层外套,通过注解的方法简化了调用的api.

4.1生成okhttp3.Call对象

  @GuardedBy("this")
  private okhttp3.Call getRawCall() throws IOException {
    okhttp3.Call call = rawCall;
    if (call != null) return call;
    ...
    // Create and remember either the success or the failure.
    try {
      return rawCall = createRawCall();
    } catch (RuntimeException | Error | IOException e) {
      throwIfFatal(e); // Do not assign a fatal error to creationFailure.
      creationFailure = e;
      throw e;
    }
  }

getRawCall调用createRawCall方法。

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

createRawCall方法调用RequestFactory的create方法生成最终的Request对象来生成okhttp3.Call。

  //RequestFactory.java
  okhttp3.Request create(Object[] args) throws IOException {
    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args.length;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException(
          "Argument count ("
              + argumentCount
              + ") doesn't match expected count ("
              + handlers.length
              + ")");
    }
    //1.构建RequestBuilder,传入初始参数
    RequestBuilder requestBuilder =
        new RequestBuilder(
            httpMethod,
            baseUrl,
            relativeUrl,
            headers,
            contentType,
            hasBody,
            isFormEncoded,
            isMultipart);

    if (isKotlinSuspendFunction) {
      // The Continuation is the last parameter and the handlers array contains null at that index.
      argumentCount--;
    }

    //2.解析每一个参数,调用ParameterHandler的apply方法
    List<Object> argumentList = new ArrayList<>(argumentCount);
    for (int p = 0; p < argumentCount; p++) {
      argumentList.add(args[p]);
      handlers[p].apply(requestBuilder, args[p]);
    }
    //3.构建okhttp3.Request
    return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
  }

根据前面的分析,我们知道方法的每个参数都会生成一个特定的ParameterHandler实例,用来处理参数,拼接网络请求的参数。

4.2对返回数据进行数据解析处理

  //OkHttpCall.java
  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ...
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      //解析数据
      T body = responseConverter.convert(catchingBody);
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }

这里也很简单,responseConverter就是前面【2.2.2.2生成Converter】生成Converter转换器的对象。对返回数据进行数据解析,在本文提供的例子中:

    static final class DataAdapter implements Converter<ResponseBody, Blog> {
        @Override
        public Blog convert(ResponseBody responseBody) throws IOException {
            String body = responseBody.string();
            // FIXME: 2020/11/16 数据处理
            return new Blog(body);
        }
    }

把结果转化为Blog 对象。
到这里整个网络请求过程就算完成了,这么看来Retrofit的逻辑还算清晰,通过动态代理获取服务的实例,通过注解封装网络请求的参数。
欢迎指正,共同进步。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值