Retrofit总结

使用

官方源码

gradle配置

    implementation 'com.squareup.retrofit2:retrofit:2.9.0'

ConverterFactory和CallAdapterFactory基本都是需要另外导包的,而我们一般都会用到GsonConverterFactory,所以需要导入GsonConverterFactory依赖示例如下。

    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

以https://blog.csdn.net/Welcome_Word/article/details/120725889为例。
假设他的返回是json数据。

创建Retrofit

        String baseUrl = "https://blog.csdn.net/";
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .client(BiliOkHttpClientManager.getInstance().getNormalOkHttpClient())
                .build();

其中addConverterFactory和client是可选的,baseUrl是必须的。
如果响应数据是基本数据类型可用ScalarsConverterFactory

定义响应数据对象

根据响应的json创建相应的JavaBean对象,推荐使用插件,比如GsonFormatPlus。假设创建的对象类名为TestResult。上面的addConverterFactory就是用来将响应的json转成JavaBean。

定义接口

public interface TestRetrofitAPI {
    @GET("Welcome_Word/article/details/120725889")
    public Call<TestResult> getTestResult();
}

请求接口

        TestRetrofitAPI retrofitAPI = retrofit.create(TestRetrofitAPI.class);
//异步
        retrofitAPI.getTestResult().enqueue(new Callback<TestResult>() {
            @Override
            public void onResponse(Call<TestResult> call, Response<TestResult> response) {

            }

            @Override
            public void onFailure(Call<TestResult> call, Throwable t) {

            }
        });
//同步
//        Response<TestResult> retrofitResponse = retrofitAPI.getTestResult().execute();

这就是Retrofit的一次简单使用。
基本所有的注解都在retrofit2.http包下,如下图
在这里插入图片描述
基本都能顾名思义,FormUrlEncoded与Multipart只能同时存在一个,其中FormUrlEncoded与Field搭配使用,Multipart与Part搭配使用。下面放一些官方的使用示例

@GET("users/list?sort=desc")

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);

@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

@POST("users/new")
Call<User> createUser(@Body User user);

@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);

@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

源码简单讲解

Retrofit最核心的原理是使用了动态代理模式。所以那些请求都是定义在接口里,而不能是类。
Retrofit的基本流程是解析接口上的注解包装成RequestFactory,然后根据接口方法定义的响应数据对象寻找合适的ConverterFactory(顺序遍历,先到先得)生成Converter,然后构造OkHttpCall,由OkHttpCall负责网络请求和调用Converter将响应转成Java对象。然后根据接口定义的返回类型(比如Call还是什么)寻找合适的CallAdapterFactory(顺序遍历,先到先得)获得CallAdapter,在我们调用接口方法的时候就调用CallAdapter的T adapt(Call call)方法将适配后的对象返回,由适配的对象操作OkHttpCall。具体的可以看源码。
先看Retrofit.Builder的build方法

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

      //OkHttpClient,没有设置就默认生成一个
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      //线程调度,下面默认的CallAdapterFactory用到(默认主线程)
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      //顾名思义,适配器模式,将默认的Call转换成我们业务需要的对象,比如Observable
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories =
          new ArrayList<>(
              1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
              
      //先是BuiltInConverters然后用户配置,然后默认,注意顺序
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());

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

可以看到baseUrl是必须的。
callFactory如果我们没有通过client配置则会生成一个默认的。通过callFactory进行网络请求。
callbackExecutor处理回调的线程切换,如果没有配置则调用defaultCallbackExecutor,进Platform类里看可以发现通过主线程的Handler处理,部分代码如下

    static final class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override
      public void execute(Runnable r) {
        handler.post(r);
      }
    }

然后在callAdapterFactories的最后添加了一个defaultCallAdapterFactories(使用了callbackExecutor),这个就是默认的CallAdapterFactories,所以Retrofit默认的回调是运行在主线程的,Okhttp是在网络请求的线程。
converterFactories先是添加了一个BuiltInConverters,然后是用户配置的,然后是defaultConverterFactories
validateEagerly是配置是否需要在创建接口实例时就提前校验所有的接口方法,下面的create方法可以看到这个变量的使用。到此Retrofit创建完成。
从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.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                args = args != null ? args : emptyArgs;
                //每个方法的调用其实就是调用对应的ServiceMethod
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

直接可以看到通过动态代理返回了接口的实例。如果是Object的方法直接调用,如果是JDK8也就是API24以后才有的默认方法调用platform.invokeDefaultMethod(API26才允许调用默认方法),这里就不深究了。重点是loadServiceMethod(method).invoke(args),我们定义的接口就是走这里。把目光移回到第一句,点进validateServiceInterface方法

  private void validateServiceInterface(Class<?> service) {
    //检查class是否是接口
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }

    Deque<Class<?>> check = new ArrayDeque<>(1);
    check.add(service);
    //循环检查父类是否有泛型
    while (!check.isEmpty()) {
      Class<?> candidate = check.removeFirst();
      if (candidate.getTypeParameters().length != 0) {
        StringBuilder message =
            new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
        if (candidate != service) {
          message.append(" which is an interface of ").append(service.getName());
        }
        throw new IllegalArgumentException(message.toString());
      }
      Collections.addAll(check, candidate.getInterfaces());
    }
    //根据配置是否提前解析并生成这个class的所有方法的ServiceMethod
    if (validateEagerly) {
      Platform platform = Platform.get();
      for (Method method : service.getDeclaredMethods()) {
        if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
          loadServiceMethod(method);
        }
      }
    }
  }

上面是检查这个class是不是接口(因为动态代理生成的是Proxy的子类,所以代理对象只能是接口,单继承),还有检查泛型(不支持)。下面的validateEagerly部分就是检查和生成ServiceMethod(HttpServiceMethod)。看loadServiceMethod方法,如果我们设置了validateEagerly那么在create的时候就会生成和检查这个接口的所有方法,如果没有那就在具体方法调用的时候才生成那个方法的ServiceMethod。
点进loadServiceMethod方法

  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;
  }

可以看到对方法进行了缓存,不会重复解析,然后进去parseAnnotations方法

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    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.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

两个重点,一个是RequestFactory.parseAnnotations,一个是HttpServiceMethod.parseAnnotations。先看前者

  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

很简单,然后看build方法

      RequestFactory build() {
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              method,
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError(
              method,
              "FormUrlEncoded can only be specified on HTTP methods with "
                  + "request body (e.g., @POST).");
        }
      }

      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);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError(method, "Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError(method, "Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError(method, "Multipart method must contain at least one @Part.");
      }

      return new RequestFactory(this);
    }

可以看到开头就是遍历注解进行解析,跟进去看一下

    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;
      }
    }

这里就不继续进去了,可以发现这部分就是通过解析方法上和参数上的各种注解然后封装成RequestFactory,后面就会使用这个RequestFactory生成Okhttp的Call。
接着看HttpServiceMethod.parseAnnotations方法,这里就将上面解析出来的RequestFactory传递了进去。

  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    //就是方法的返回类型,会区分kotlin的suspend方法
    Type adapterType;
    if (isKotlinSuspendFunction) {
      Type[] parameterTypes = method.getGenericParameterTypes();
      Type responseType =
          Utils.getParameterLowerBound(
              0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
      if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
        // Unwrap the actual body type from Response<T>.
        responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
        continuationWantsResponse = true;
      } else {
        // TODO figure out if type is nullable or not
        // Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
        // Find the entry for method
        // Determine if return type is nullable or not
      }

      adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
      annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
    } else {
      adapterType = method.getGenericReturnType();
    }
    
    //根据方法的返回类型找到适配的callAdapter
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
    //根据callAdapter获取响应所应该转换成的JavaBean类型
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(
          method,
          "'"
              + getRawType(responseType).getName()
              + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

    //根据responseType获取responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);

    //配置的okHttpClient,负责网络请求
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
      //我们正常的方法是走这里,下面是kotlin的suspend方法。
      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);
    }
  }

上面这部分主要是确定了RequestFactory,callFactory(OkHttpClient),Converter和CallAdapter,然后根据这几个参数实例化一个HttpServiceMethod。看一下HttpServiceMethod和CallAdapted(继承HttpServiceMethod)

//HttpServiceMethod的invoke方法
  @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  
//CallAdapted的adapt实现
    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }

到这里基本可以说Retrofit的分析就结束了。每个接口方法的调用就是通过requestFactory(根据注解生成),方法传参,callFactory(OkHttpClient),responseConverter(响应转换器)构建OkHttpCall(Retrofit定义的Call包装),然后调用callAdapter的adapt方法返回我们需要的对象,比如Call或者Observable什么的。
其中responseConverter在OkHttpCall里用到,部分代码如下

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

    // Remove the body's source (the only stateful object) so we can pass the response along.
    rawResponse =
        rawResponse
            .newBuilder()
            .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
            .build();

    int code = rawResponse.code();
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }

    if (code == 204 || code == 205) {
      rawBody.close();
      return Response.success(null, rawResponse);
    }

    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;
    }
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值