Retrofit source code analysis & summary

Retrofit source code analysis & summary

Introduction

Retrofit is a secondary encapsulation of Okhttp network requests. It simplifies the use of Okhttp through annotations + dynamic proxy, making it possible to request network interfaces like calling interfaces through simple configuration. In addition, Retrofit also supports RxJava and Coroutines in kotlin

basic use

  1. Import dependent libraries
//网络请求
implementation 'com.squareup.retrofit2:retrofit:2.9.0'//Retrofit基本库
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'//用于将结果转换成对象
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'//用于转换成RxJava支持的Observer对象
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'//RxJava对Android的支持
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'//Okhttp日志拦截器,用于打印接口请求相关log
//协程
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'//Retrofit对Kotlin协程的支持
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'//协程对Android的支持
implementation('androidx.lifecycle:lifecycle-runtime-ktx:2.6.0-alpha02')//协程对LifeCycle的支持
  1. Define a service interface for network requests
package com.example.myapplication.retrofit

import android.service.autofill.UserData
import io.reactivex.Observable
import retrofit2.Call
import retrofit2.http.*

interface IUserServer {
    /**
     * 以GET方式请求
     */
    @GET("getUserInfo/")
    fun getUserInfo(@Query("userId") userId: String): Call<UserData>

    /**
     * 以POST方式请求,并结合RxJava
     */
    @POST("getUserInfo/")
    @FormUrlEncoded
    fun getUserInfoByRxJava(@Field("userId") userId: String): Observable<UserData>

    /**
     * 结合kotlin协程完成线程切换
     */
    @GET("banner/json")
    suspend fun getUserInfoBySuspend2(@Query("userId") userId: String): UserData

}
  1. Create a Retrofit object and a custom interface proxy implementation object
val retrofit = Retrofit.Builder()
    .baseUrl("http://www.xxx.com/")
    .addConverterFactory(GsonConverterFactory.create())//支持Gson
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//支持Rxjava
    .build()
val server = retrofit.create(IUserServer::class.java)
  1. Commonly initiate a network request
val userInfo = server.getUserInfo("1").execute()//同步执行
server.getUserInfo("1").enqueue(object : Callback<UserData> {//异步执行
    override fun onResponse(call: Call<UserData>, response: Response<UserData>) {
        //网络请求返回结果
    }

    override fun onFailure(call: Call<UserData>, t: Throwable) {
        //网络请求错误
    }
})
  1. Combined with RxJava
server.getUserInfoByRxJava("1").subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<UserData> {
    override fun onSubscribe(d: Disposable?) {
        //网络请求前
    }

    override fun onNext(value: UserData?) {
        //网络请求返回结果
    }

    override fun onError(e: Throwable?) {
        //网络请求错误
    }

    override fun onComplete() {
        //网络请求结束
    }
})
  1. Combining with Kotlin coroutines
lifecycleScope.launch {
    val userInfo = withContext(Dispatchers.IO) {
        val userInfo = server.getUserInfoBySuspend2("1")//子线程中请求网络
    }
    //回到主线程
    Log.i("testRetrofit", "userInfo:$userInfo")
}

Core source code analysis

1. The Retrofit.create method creates a dynamic proxy for the interface we declare according to the annotation

```
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);//开始解析该方法并返回接口请求对象,比如Call、Observable(需结合Rxjava)
          }
        });
}
```
  • In the validateServiceInterface method, if Retrofit.Builder().validateEagerly(true) is configured, all the methods defined in the interface will be parsed immediately according to the annotations. If false, the methods in the interface will be parsed only when the method is called;

    The advantage of setting it to true is that when creating an interface proxy, you can check whether the annotations and return values ​​of each method configuration are correct. If it is false by default, the problem can only be found when the method is called;

    Therefore, it is recommended to set it to true in the debug phase to find problems early, and to set false in the release phase to improve performance

    private void validateServiceInterface(Class<?> service) {
        ... ...
        if (validateEagerly) {
          Platform platform = Platform.get();
          for (Method method : service.getDeclaredMethods()) {//遍历所有方法,根据注解进行解析
            if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
              loadServiceMethod(method);
            }
          }
        }
    }
    
  • The Call returned by the interface in the default implementation is actually an interface defined in Retrofit, which defines the method of synchronous request and asynchronous request;

    public interface Call<T> extends Cloneable {
      ... ...
      /**
       * Synchronously send the request and return its response.
       *
       * @throws IOException if a problem occurred talking to the server.
       * @throws RuntimeException (and subclasses) if an unexpected error occurs creating the request or
       *     decoding the response.
       */
      Response<T> execute() throws IOException;
    
      /**
       * Asynchronously send the request and notify {@code callback} of its response or if an error
       * occurred talking to the server, creating the request, or processing the response.
       */
      void enqueue(Callback<T> callback);
      ... ...
    }
    
  • The implementation class of Call is determined by whether there is an annotation @SkipCallbackExecutor. When there is this annotation, the implementation class of Call is OkHttpCall.java, which encapsulates the network request of OkHttp. If there is no such annotation, the implementation class of Call is DefaultCallAdapterFactory.ExecutorCallbackCall; This class is just a proxy class, and it is OkHttpCall that actually implements network requests;
    the meaning of the proxy class is that after Okhttp makes an asynchronous request and returns the result, it will first switch the thread to the main thread through the Handler and then return the result

    final class OkHttpCall<T> implements Call<T> {
        @Override
        public void enqueue(final Callback<T> callback) {
            ...
            okhttp3.Call call;
            call.enqueue(
            new okhttp3.Callback() {
              @Override
              public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
              }
              @Override
              public void onFailure(okhttp3.Call call, IOException e) {
                callFailure(e);
              }
            }
            ...
        }
    
        @Override
        public Response<T> execute() throws IOException {
        okhttp3.Call call;
        ...
        return parseResponse(call.execute());
      }
    }
    
    static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor;//在主线程执行,实现类是Platform.Android.MainThreadExecutor
        final Call<T> delegate;//这个实现类是OkHttpCall
    
        @Override
        public void enqueue(final Callback<T> callback) {
          delegate.enqueue(
              new Callback<T>() {
                @Override
                public void onResponse(Call<T> call, final Response<T> response) {
                  callbackExecutor.execute(() -> {
                        //切换到主线程执行
                          callback.onResponse(ExecutorCallbackCall.this, response);
                        }
                      });
                }
    
                @Override
                public void onFailure(Call<T> call, final Throwable t) {
                  //切换到主线程执行
                  callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
                }
              });
        }
    
        @Override
        public Response<T> execute() throws IOException {
          return delegate.execute();//在当前所在线程执行
        }
    }
    

2. The analysis process and use of annotations

  • In the Retrofit.create method, the loadServiceMethod method will first look up the ServiceMethod object from the cache, if it has been parsed before, it will return directly, if not, call the ServiceMethod.parseAnnotations method to return a ServiceMethod object

    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;
    }
    
  • Then the RequestFactory.parseAnnotations method will be called to actually parse the annotations, and build an HttpServiceMethod object to return

    abstract class ServiceMethod<T> {
      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);
    }
    
  • The annotations in the parsing method in RequestFactory.Builder can be understood as the RequestFactory object holds all requested data

    final class RequestFactory {
      static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
        return new Builder(retrofit, method).build();
      }
      static final class Builder {
        final Annotation[] methodAnnotations;//方法上的注解
        final Annotation[][] parameterAnnotationsArray;//方法参数上的注解
        final Type[] parameterTypes;//参数类型
        @Nullable String httpMethod;//请求的方式get、post等
        @Nullable String relativeUrl;//解析处理后的请求接口
        @Nullable Headers headers;//封装的请求头信息
        boolean isKotlinSuspendFunction; //用于标记是否kotlin协程中suspend方法
        ...
        private Headers parseHeaders(String[] headers) {}//解析请求头信息
        private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) //解析请求方式和接口路径
        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);
          }
          ...
        }
        private ParameterHandler<?> parseParameterAnnotation(){//解析参数上注解
            if (annotation instanceof Path) {
            } else if (annotation instanceof Query) {
            } else if (annotation instanceof QueryName) {
            } else if (annotation instanceof QueryMap) {
            } else if (annotation instanceof Header) {
            } else if (annotation instanceof HeaderMap) {
            } else if (annotation instanceof Field) {
            } else if (annotation instanceof FieldMap) {
            }  else if (annotation instanceof Body) {
            }
            ...
        }
      }
    }
    
  • The use of request parameters is to encapsulate all request parameters into an OkHttp Request object through the RequestFactory.create method when the OkhttpCall.createRawCall() method is actually initiated to create the Okhttp Call object

class OkHttpCall{
    private okhttp3.Call createRawCall() throws IOException {
        okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
        return call;
    }
}
class RequestFactory{
    okhttp3.Request create(Object[] args) throws IOException {
        RequestBuilder requestBuilder =
            new RequestBuilder(
                httpMethod,
                baseUrl,
                relativeUrl,
                headers,
                contentType,
                hasBody,
                isFormEncoded,
                isMultipart);

        if (isKotlinSuspendFunction) {//协程suspen方法会自动在最后面加一个Continuation对象类型参数,所以实际请求时要去掉
          // 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]);
        }
        //构建okhttp3.Request对象
        return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
    }
}

3. RxJava2CallAdapterFactory: Support for Rxjava, convert the Call object returned by default into an Observer object

  • When calling the interface method, the invoke method of HttpServiceMethod.CallAdapted will be called by default through the dynamic proxy, and CallAdapted inherits from HttpServiceMethod and rewrites the adapt method; the adapt method is
    used to encapsulate the Call object and convert the result into the interface method we defined the declared return object
class HttpServiceMethod{
 @Override
  final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }

  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);

  static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;//默认的适配器是通过DefaultCallAdapterFactory动态生成的CallAdapter实现类

    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;//通过RxJava2CallAdapterFactory生成的Rxjava2适配器RxJava2CallAdapter
    }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);//调用适配器,将返回结果转换成我们定义的返回类型,比如默认是返回Call,Rxjava返回的是Observer对象
    }
  }
}
  • When RxJava2CallAdapterFactory is created, you can choose to call create, createAsync, createWithScheduler (Scheduler) methods to create. The main difference between them is that create calls the Call.execute method to request the network, that is, executes in the current thread; and createAsync calls
    Call.enqueue The method requests the network, that is, an asynchronous request; createWithScheduler can pass in a Scheduler to specify which thread the network request is executed on, and implement it through observable.subscribeOn(scheduler)
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
  /**
   * Returns an instance which creates synchronous observables that do not operate on any scheduler
   * by default.
   */
  public static RxJava2CallAdapterFactory create() {
    return new RxJava2CallAdapterFactory(null, false);
  }

  /**
   * Returns an instance which creates asynchronous observables. Applying
   * {@link Observable#subscribeOn} has no effect on stream types created by this factory.
   */
  public static RxJava2CallAdapterFactory createAsync() {
    return new RxJava2CallAdapterFactory(null, true);
  }

  public static RxJava2CallAdapterFactory createWithScheduler(Scheduler scheduler) {
    if (scheduler == null) throw new NullPointerException("scheduler == null");
    return new RxJava2CallAdapterFactory(scheduler, false);
  }

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    ...
    return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
        isSingle, isMaybe, false);
  }
}
  • Call the RxJava2CallAdapter.adapt method, pass the Call in and return the Observer
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
    @Override public Object adapt(Call<R> call) {
    Observable<Response<R>> responseObservable = isAsync
        ? new CallEnqueueObservable<>(call)
        : new CallExecuteObservable<>(call);//真正网络请求包装在在这里面
        ...
        Observable<?> observable;
        if (isResult) {
          observable = new ResultObservable<>(responseObservable);
        } else if (isBody) {
          observable = new BodyObservable<>(responseObservable);
        } else {
          observable = responseObservable;
        }

        if (scheduler != null) {
          observable = observable.subscribeOn(scheduler);
        }
        ...
        return observable;
    }
}
  • When the subscribe method of Observer is called externally, the subscribeActual method in CallExecuteObservable/CallExecuteObservable will be executed immediately, thereby calling the execute or enqueue method of Call to realize the network request
class Observable{
    public final void subscribe(Observer<? super T> observer) {
        subscribeActual(observer);
    }
}

final class CallExecuteObservable<T> extends Observable<Response<T>> {
    @Override protected void subscribeActual(Observer<? super Response<T>> observer) {
        Call<T> call = originalCall.clone();
        Response<T> response = call.execute();//发起网络请求并返回结果
        if (!call.isCanceled()) {//传递给onNext方法
            observer.onNext(response);
          }
          if (!call.isCanceled()) {
            terminated = true;
            observer.onComplete();
          }
    }
}

4. GsonConverterFactory: Processing of network request return results

  • After OkHttpCall initiates a network request, it will call the parseResponse method to parse the returned result, and then convert it through the result converter. The default converter is BuiltInConverters. If GsonConverterFactory is configured, it supports conversion into our custom object. The implementation class is GsonResponseBodyConverter
class OkHttpCall{
    @Override
  public Response<T> execute() throws IOException {
    okhttp3.Call call;
    call = getRawCall();
    ...
    return parseResponse(call.execute());
  }

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
    ResponseBody rawBody = rawResponse.body();
    ...
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
      //调用结果转换器进行转换,这里会根据声明方法返回值类型选择不同转换器,比如返回默认的ResponseBody,则使用自带的BuiltInConverters转换,返回自定义对象则会使用GsonResponseBodyConverter进行转换
      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;
    }
  }
}
  • Retrofit's built-in default converter, BuiltInConverters, supports processing the return type of ResponseBody/Void or kotlin's Unit
final class BuiltInConverters extends Converter.Factory {
  /** Not volatile because we don't mind multiple threads discovering this. */
  private boolean checkForKotlinUnit = true;

  @Override
  public @Nullable 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;
    }
    if (checkForKotlinUnit) {
      try {
        if (type == Unit.class) {
          return UnitResponseBodyConverter.INSTANCE;
        }
      } catch (NoClassDefFoundError ignored) {
        checkForKotlinUnit = false;
      }
    }
    return null;
  }
}
  • Gson converter GsonResponseBodyConverter, supports conversion of custom object types
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;

  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }
}

5. Support for kotlin coroutines

  • Determine whether the kotlin suspend method is used. In kotlin, the suspend modified method will be compiled into bytecode and decompiled into java code, and it will be found that there will be a Continuation type parameter in the method parameter at the end, which is used to support the coroutine
kotlin字节码反编译后的java代码
public interface IUserServer {
    ... ...

   @GET("banner/json")
   @Nullable
   Object getUserInfoBySuspend2(@Query("userId") @NotNull String var1, @NotNull Continuation var2);
}
  • Retrofit makes judgments when RequestFactory parses method parameters
class RequestFactory{
    class Builder{
        boolean isKotlinSuspendFunction;
        private @Nullable ParameterHandler<?> parseParameter(
        int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
            try {
                if (Utils.getRawType(parameterType) == Continuation.class) {//判断是否suspend协程方法
                  isKotlinSuspendFunction = true;
                  return null;
                }
            } catch (NoClassDefFoundError ignored) {
            }
        }
    }
}
  • According to the return type of the method, different HttpServiceMethods are returned. When the suspend method directly returns a custom data type (such as UserData), the SuspendForBody object is returned; if the method returns Response, the SuspendForResponse object is returned. These two return objects are actually similar , but the return type is different
class HttpServiceMethod{
    static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
        boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
        boolean continuationWantsResponse = false;
        if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
            // Unwrap the actual body type from Response<T>.
            responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
            continuationWantsResponse = true;
        }
        if (continuationWantsResponse) {
          //返回Response<UserData>类型结果
          return (HttpServiceMethod<ResponseT, ReturnT>)
              new SuspendForResponse<>(
                  requestFactory,
                  callFactory,
                  responseConverter,
                  (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
        } else {
          //返回UserData类型结果
          return (HttpServiceMethod<ResponseT, ReturnT>)
              new SuspendForBody<>(
                  requestFactory,
                  callFactory,
                  responseConverter,
                  (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
                  continuationBodyNullable);
        }
    }
}
  • Continue to analyze with SuspendForBody, when the adapt method is called, Retrofit will call the kotlin extension method await/awaitNullable
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
    private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
    private final boolean isNullable;

    @Override
    protected Object adapt(Call<ResponseT> call, Object[] args) {
      call = callAdapter.adapt(call);//这里是默认的DefaultCallAdapterFactorys产生的Adapter
      //获取suspend最后一个参数用于协程
      Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
      try {//调用Retrofit使用kotlin对Call类的扩展方法
        return isNullable //返回的对象是否可为空
            ? KotlinExtensions.awaitNullable(call, continuation)
            : KotlinExtensions.await(call, continuation);
      } catch (Exception e) {
        return KotlinExtensions.suspendAndThrow(e, continuation);
      }
    }
}
  • Kotlin extends the analysis of the Call method. The coroutine method will initiate a network request asynchronously and return the result. When it is finished, it will resume execution at the parent coroutine.
//这里是suspend方法,执行时协程会挂起
suspend fun <T : Any> Call<T>.await(): T {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()//设置协程取消时的回调,调用Call的cancel方法
    }
    enqueue(object : Callback<T> {//调用Call方法异步请求网络
      override fun onResponse(call: Call<T>, response: Response<T>) {
        if (response.isSuccessful) {
          val body = response.body()
          if (body == null) {
            val invocation = call.request().tag(Invocation::class.java)!!
            val method = invocation.method()
            val e = KotlinNullPointerException("Response from " +
                method.declaringClass.name +
                '.' +
                method.name +
                " was null but response body type was declared as non-null")
            continuation.resumeWithException(e)//恢复协程并抛出异常
          } else {
            continuation.resume(body)//恢复协程并返回结果
          }
        } else {//恢复协程并抛出异常
          continuation.resumeWithException(HttpException(response))
        }
      }

      override fun onFailure(call: Call<T>, t: Throwable) {
        continuation.resumeWithException(t)//恢复协程并抛出异常
      }
    })
  }
}

summary

  • Retrofit implementation principle:
    Answer: When Retrofit creates our custom interface instance through the Create method, it will create a dynamic proxy for our interface; when calling the interface method, it will first analyze the information of this method according to the configuration annotation, including the request path, Request parameters, return values, etc., and encapsulate the parsed information into an object and cache it;
    then encapsulate it into a Call object according to the information of the method. The default implementation class of this Call object is OkHttpCall, and internally initiates synchronously or asynchronously through Okhttp Network request;
    then call Call's execute synchronous or enqueue asynchronous method to make a network request. After returning the result, the converter will be called to convert the result. The default is to return ResponseBody, or it can be converted to our custom type by configuring the Gson converter;
    if To support RxJava and return the Observer object, you need to configure a CallAdapter of Rxjava, encapsulate the Call object into the Observer object in the adapter and return it, when the subscribe method of the Observer is called, it will trigger the network request operation of Call, and finally pass RxJava Distribution of results;
    if support for kotlin coroutines is required, Retrofit will judge whether to suspend the method when parsing the method. If so, it will execute the kotlin extension method of Call, which is also of suspend type, and the coroutine will be suspended in the extension method Process, perform network request operations through the Call object, and finally resume the coroutine to the place called by the parent coroutine through the Continuation.resume method

  • What is the difference between a static proxy and a dynamic proxy?
    Answer: Static proxy means that when the code is written, the relationship between the proxy class and the proxied class is determined, and the proxy class bytecode file will be generated after compilation; while dynamic proxy means that during runtime, it is dynamically passed through reflection Generate a proxy class for the proxied interface. When the method of this interface is called, it will enter the invoke method of InvokeHandler, so as to realize the unified processing of the proxied interface; static proxy is suitable for the situation that the proxied class is relatively small,
    if There are many types of agents, and there is no need for unified processing, so dynamic agents are much more convenient

  • How does Retrofit return the result and switch to the main thread?
    Answer: Retrofit will judge whether it is an Android platform through system properties. If it is an Android platform, it will create an executor, which will create a Handler for the main thread Looper internally. When the network request ends and returns the result, it will encapsulate a Runnable through this main thread. Thread Handler to execute, thus switching to the main thread;
    or thread switching through RxJava or coroutine

  • Support for Kotlin coroutines (suspend method)

    • Determine the condition of the coroutine method: determine whether the last parameter of the method is of Continuation.class type
    • Retrofit uses kotlin to extend the suspend method of the Call class, execute the network request of Call in the suspend method, and then resume the suspension of the coroutine through the resume method of Continuation and return the result
    • When did you switch back to the main thread? After calling the continuation.resume method in the coroutine, it will automatically return to the thread where its parent coroutine is located, that is, the main thread continues to execute

おすすめ

転載: blog.csdn.net/guangdeshishe/article/details/129903236