Retrofit 是什么?

Retrofit担任将HttpAPI接口转化为Java接口,它是一个RESTful风格的Http网络恳求结构的封装,实际上的网络恳求仍是由OkHttp完结,Retrofit仅担任网络接口恳求的封装。

  • App 中经过Retrofit恳求网络,实际上是运用Retrofit接口层封装恳求参数、HeaderUrl 等信息,之后由 OkHttp 完结后续的恳求操作。
  • 在服务端回来数据之后,OkHttp 将原始的成果交给 RetrofitRetrofit依据用户的需求对成果进行解析。

所以,网络恳求的本质仍旧是 OkHttp 完结的,Retrofit 仅仅帮运用者来进行作业简化的,比方配置网络,处理数据等作业,进步这一系列操作的复用性。

如何运用 Retrofit

  1. 引入依赖
implementation 'com.squareup.okhttp3:okhttp:+'// OkHttp网络库
implementation 'com.squareup.retrofit2:retrofit:+'// retrofit库
implementation 'com.google.code.gson:gson:+'// gson生成和解析库
implementation 'com.squareup.retrofit2:converter-gson:+'//Gson转化器,恳求成果转化为数据Model
implementation 'com.squareup.retrofit2:adapter-rxjava2:+'// 配合Rxjava运用
implementation 'io.reactivex.rxjava3:rxjava:+'//
implementation 'io.reactivex.rxjava3:rxandroid:+'//一个帮助做异步恳求的结构,类似于AsyncTask
  1. 创立 API 恳求接口

RetrofitHttp 恳求抽象成 Java 接口:采用注解描述网络恳求参数和配置网络恳求参数

//自己界说的 API 恳求接口
interface MyApiService {
    @GET("{source}/media/list")
    fun getMediaList(@Path("source") source: String): Call<List<Media>>
}
  1. 创立 Retorfit 实例,并发送恳求
//1. 创立Retrofit实例
val retrofit = Retrofit.Builder()
    .baseUrl("http://api.test.com/") //设置网络恳求的Url地址
    .addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
    .build()
//2. 创立MyApiService目标
val apiService = retrofit.create(MyApiService::class.java)
//3. 获取Call目标
val mediaList = apiService.getMediaList("qqm")
//4. 调用call.enqueue建议异步恳求
mediaList.enqueue(object: Callback<List<Media>> {
    override fun onResponse(call: Call<List<Media>>, response: Response<List<Media>>) {
        Log.d(TAG, "mediaList response code is ${response.code()}")
    }
    override fun onFailure(call: Call<List<Media>>, t: Throwable) {
        Log.e(TAG, "mediaList failure")
    }
})

Retrofit 的中心概念

注解

Retrofit 运用注解来描述 HTTP 恳求的参数、URL 和恳求办法。以下是常见的注解:

  • @GET:发送 GET 恳求
  • @POST:发送 POST 恳求
  • @Path:替换 URL 中的参数
  • @Query:增加查询参数
  • @Body:发送恳求体
public interface ApiService {
 @GET("posts/{id}")
 Call<Post> getPostById(@Path("id") int postId);
}

CallAdapter

  • CallAdapter 主要用于将 RetrofitCall 类型适配到其他类型,例如 LiveDataRxJavaObservable 等,Retrofit 内置了常见的 CallAdapter,如 RxJavaCallAdapterLiveDataCallAdapter
  • 运用场景: 当你希望在进行网络恳求时,直接得到一个特定类型的呼应,而不是 Retrofit 默许的 Call 类型时,就能够运用 CallAdapter
Retrofit retrofit = new Retrofit.Builder()
 .baseUrl(BASE_URL)
 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
 .build();

Converter

  • 作用: Converter 主要用于将恳求体和呼应体进行转化,将网络恳求的原始数据转化为你需求的实体目标,以及将实体目标转化为网络恳求的原始数据。
  • 运用场景: 当你需求自界说恳求体和呼应体的转化逻辑时,能够运用 Converter
  • 示例: 假如你的服务器回来的是 JSON 数据,你能够运用 GsonConverterFactory 将 JSON 数据转化为 Java 目标。
Retrofit retrofit = new Retrofit.Builder()
 .baseUrl(BASE_URL)
 .addConverterFactory(GsonConverterFactory.create())
 .build();

源码分析

触及到的类及重要办法

  • IMyApiService:自界说的 API 接口,经过注解声明网络恳求

  • Retrofit:经过内部 Builder.build 构建

    • create办法:经过动态署理,生成 IMyApiService 的署理类;

    • loadServiceMethod办法:ServiceMethod 能够浅显的理解为咱们在 API 接口中界说的办法完成,loadServiceMethod 办法调用缓存或新建的 ServiceMethod 实例

  • ServiceMethod:能够浅显的理解为咱们在 API 接口中界说的办法完成,但它是一个类

    • parseAnnotations办法:创立 RequestFactory 实例,并调用 HttpServiceMethod.parseAnnotations 回来 ServiceMethod 实例。

  • HttpServiceMethod:承继自 ServiceMethod

    • parseAnnotations办法:解析注解的办法,获取所有注解,内部继续调用 createCallAdapter,创立 CallAdapter 目标,最终回来 CallAdapted 内部类或者 SuspendForResponse 内部类(kotlin 协程调用),这两个内部类都承继自 HttpServiceMethod,均包含 requestFactory / callFactory / responseConverter / callAdapter

  • Call/OkHttpCallRetrofit 结构内的 Call 接口,非 OkHttp 内部的 Call

    • public interface Call<T> extends Cloneable {
              Response<T> execute() throws IOException;
              void enqueue(Callback<T> callback);
              boolean isExecuted();
              void cancel();
              boolean isCanceled();
              Call<T> clone();
              Request request();
              Timeout timeout();
        }
      
    • Call 内部根本上和 OkHttp3.Call 接口一致,有同步履行办法 execute,也有异步网络恳求办法 enqueue,这个 Call 接口的完成是 ****OkHttpCall

Retrofit.create

retrofit2.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;
              return platform.isDefaultMethod(method)
                  ? platform.invokeDefaultMethod(method, service, proxy, args)
                  : loadServiceMethod(method).invoke(args);
            }
          });
}

create 办法中,运用动态(运行期)署理,完成自界说 API 接口的详细代码:

  1. 经过Proxy.newProxyInstance 创立 IMyService 的动态署理完成类;

  2. 当咱们调用 apiService.getMediaList("qqm")办法时,完成类内部会调用 ****InvocationHandle ****拦截到对应的办法和参数信息,调用 invoke 办法

  3. invoke 办法中,调用 loadServiceMethod.invoke,这个办法会获取 API 办法上的注解,去拼成一个正常的 OkHttp 恳求

retrofit2.Retrofit#loadServiceMethod

ServiceMethod<?> loadServiceMethod(Method method) {
  //1.  
  ServiceMethod<?> result = serviceMethodCache.get(method);
  if (result != null) return result;
  synchronized (serviceMethodCache) {
    result = serviceMethodCache.get(method);
    if (result == null) {
       //2. 
      result = ServiceMethod.parseAnnotations(this, method);
      // 3.
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}
  1. 从缓存 ConcurrentHashMap 中获取 ServiceMethod

  2. 经过 ServiceMethod.parseAnnotations(this,method),新建 ServiceMethod 目标;

  3. 将新建的 ServiceMethod 实例放入缓存 ConcurrentHashMap 中,以便下次复用

ServiceMethod.parseAnnotations

retrofit2.ServiceMethod#parseAnnotations

static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
  // 1. 
  RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
  ...
 // 2. 
  return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
  1. 经过 RequestFactory.parseAnnotations(retrofit,method)办法新建 RequestFactory 实例,

    1. RequestFactory能够看成是 Retrofit 结构中构建 OkHttp 恳求的工厂类,其间包含一个create 办法,用于创立 OkHttp request
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
            + ")");
  }
  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--;
  }
  List<Object> argumentList = new ArrayList<>(argumentCount);
  for (int p = 0; p < argumentCount; p++) {
    argumentList.add(args[p]);
    handlers[p].apply(requestBuilder, args[p]);
  }
  return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
  1. parseAnnotations:调用内部 Builder.build办法,去解析 API 办法上的注解,解析包含是 GET 仍是 POST 办法,Header 有什么,恳求链接是什么等,将其赋值给 Builder 内的 headers/method/contentType 等变量,用于后续构建恳求体
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {   return new Builder(retrofit, method).build(); }
Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
// retrofit2.RequestFactory.Builder#build
RequestFactory build() {
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }
  ...
  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);
  }
  ...
  return new RequestFactory(this);
}
  1. HttpServiceMethod.parseAnnotations(retrofit,method,requestFactory)新建 HttpServiceMethod 实例(承继自 ServiceMethod

调用 HttpServiceMethod.parseAnnotations,并将对应的 Retrofit/Method/RequestFactory 目标传入:

// retrofit2.HttpServiceMethod#parseAnnotations
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();
  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<ResponseT, ReturnT> callAdapter =
      createCallAdapter(retrofit, method, adapterType, annotations);
  Type responseType = callAdapter.responseType();
  Converter<ResponseBody, ResponseT> responseConverter =
      createResponseConverter(retrofit, method, responseType);
// 1. 
  okhttp3.Call.Factory callFactory = retrofit.callFactory;
  if (!isKotlinSuspendFunction) {
  // 2. 
    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);
  }
}
  1. 经过 retrofit 获取 okhttp3.Call.Factory 目标,实际上便是 OkHttpClient 实例

  2. 假如不是 Kotlinsuspend 函数,回来 CallAdapted 目标(HttpServiceMethod 的子类),不然回来 SuspendForBody 目标(同样是 HttpServiceMethod 的子类)

HttpServiceMethod.invoke

追寻了一连串的源码,咱们经过 loadService 办法取得了 HttpServiceMethod,而后调用其invoke 办法:

@Override
final @Nullable ReturnT invoke(Object[] args) {
 //1. 新建OkHttpCall实例
  Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
  //2.
  return adapt(call, args);
}
  1. 新建 OkHttpCall 实例,参数包含前述步骤创立的 RequestFactory 实例, OkHttpClient,呼应转化器以及恳求参数;

  2. 调用adapt(call,args)办法回来调用成果,该办法有多个完成,咱们以 CallAdapted 类为例进行说明:

    1. // retrofit2.HttpServiceMethod.CallAdapted#adapt
      @Override
      protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
        return callAdapter.adapt(call);
      }
      

调用 callAdapter.adapt(call),没有增加 CallAdapter 时,运用默许的CallAdapter.adapt

//retrofit2.CallAdapter#adapt
@Override
public Call<Object> adapt(Call<Object> call) {
  return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}

回来ExecutorCallbackCall 实例。

至此,就完结了 apiService.getMediaList 的调用

接着,咱们调用 Call.enqueue,即ExecutorCallbackCall.enqueue

Call.enqueue


//retrofit2.DefaultCallAdapterFactory.ExecutorCallbackCall#enqueue
@Override
public void enqueue(final Callback<T> callback) {
  Objects.requireNonNull(callback, "callback == null");
  delegate.enqueue(
      new Callback<T>() {
        @Override
        public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(
              () -> {
                if (delegate.isCanceled()) {
          callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
                } else {
             callback.onResponse(ExecutorCallbackCall.this, response);
                }
              });
        }
        @Override
        public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
        }
      });
}

整个调用仍是经过 delegate.enqueue,即 OKHttpCall.enqueue 办法完结:

public void enqueue(final Callback<T> callback) {
  Objects.requireNonNull(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 {
      // 1. 
        call = rawCall = createRawCall();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }
  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }
  if (canceled) {
    call.cancel();
  }
// 2. 
  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) {
            throwIfFatal(e);
            callFailure(e);
            return;
          }
          try {
            callback.onResponse(OkHttpCall.this, response);
          } catch (Throwable t) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }
        @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) {
            throwIfFatal(t);
            t.printStackTrace(); // TODO this is not great
          }
        }
      });
}
  1. 经过 createRawCall 创立 OkHttp3 Call 实例:
//retrofit2.OkHttpCall#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;
}

经过 callFactory(即 OkHttpClient)创立 RealCall 目标,即 OkHttp 根本运用的流程。

  1. 得到 RealCall 目标后,调用 RealCall.enqueue 办法,得到呼应成果,并在 OkHttpCallbak 中,调用 Retrofit 中的 Callback

至此,整个 Retrofit 的网络恳求完结

总结

用户界说注解接口,用于声明Http恳求,而Retrofit经过动态署理生成注解接口的署理类,用户建议API调用时,会经过动态署理完成类中的InvocationHandler类中的invoke 办法中,调用loadServiceMethod.invoke,这个办法会获取 API 办法上的注解,去拼成一个正常的 OkHttp 恳求,在这个过程中,触及:

  1. RequestFactory :构建OkHttp Request的工厂类,其间包含parseAnnotations办法用于解析注解;
  2. HttpServiceMethod:能够经过HttpServiceMethod.invoke 取得HttpServiceMethod 实例,而后调用其invoke办法,invoke办法中构建OkHttpCall实例,并回来ExecutorCallbackCall恳求成果,咱们调用ExecutorCallbackCall.enqueue取得回来成果;
  3. Call.enqueue:其实是OkHttpCall.enqueue的包装,包含回来成果的回调也是对OkHttpCall回调的包装;