This article is based on com. Squareup. Retrofit2: retrofit: 2.9.0 version

Retrofit

Retrofit retrofit = new Retrofit.Builder().baseUrl("\"https://api.github.com/\"").build();
        ApiService apiService = retrofit.create(ApiService.class);
        Call<Response> call = apiService.queryData("");
        call.enqueue(new Callback<List<Response>>() {
            @Override
            public void onResponse(Call<List<Response>> call, Response<List<Response>> response) {

            }

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

            }
        });
Copy the code

The code above is a simple use of Retrofit, which goes like this: ApiService is the interface file that defines the request methods. We create an ApiService object from RetroFit, and then Call the request method queryData we created from ApiService and return a Call object. The call object’s enQueue method is then called to send the network request. So the key part of the whole process is the enqueue function, which sends our internal data to the network, so let’s start with the Enqueue function

1. The enqueue function

If we enter the enqueue function in the source code by Ctrl+W or Ctrl+ left mouse button, it looks like this

public interface Call<T> extends Cloneable {
/**
   * 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);
 }
Copy the code

This is an interface file called Call, and enqueue is a method in the interface that needs to be implemented, so we’re going to find out where this method is actually implemented

2, the retrofit. The create (ApiService. Class);

The enQueue function is called by the Call object, which is created by apiService calling queryData

Call<Response> call = apiService.queryData("");
Copy the code

ApiService objects are created by retrofit.create(apiService. Class), and the create function takes a class file as an argument. How do you create an object

  ApiService apiService = retrofit.create(ApiService.class);
Copy the code

When we click on the source code, it looks like this

  • ValidateServiceInterface () function to roughly two functions: 1, is the incoming ApiService. The class has carried on the various calibration, mainly is the interface file, interfaces and father have generic type parameters. 2, There is a validategbit/s switch, which, when turned on, allows us to check each request method defined during compilation. The key code is the loadServiceMethod() function.
  • Proxy.newProxyInstance is the key to realize dynamic Proxy. First of all, dynamic Proxy is to dynamically generate a Proxy object of class file in the process of program running, such as the dynamic generation of ApiService object here.

The proxy. newProxyInstance function takes three arguments: ClassLoader Loader: Class
[] interfaces: a proxy class can implement multiple interfaces at the same time, passing in a collection of interface files for the proxy implementation. Retrofit has only one interface, which is the interface where all requested methods are placed. A listener that executes a method in a proxy object and gets a callback to the invOK function in the listener that returns the proxy object

So let’s focus on the invoke function: The first if criterion refers to the method corresponding to object. class, we call invoke and return the corresponding proxy Object. We pass an interface, so we don’t go to the if criterion. IsDefaultMethod (method). This platform object is created by a function that determines the current platform, in this case an Android() object, i.e. platform = Android(). LoadServiceMethod (method).invoke(args) == The HttpServiceMethod subclass of ServiceMethod implements the invoke() method. What does the invoke() method do

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); }}); }Copy the code
private final Platform platform = Platform.get();
class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    return "Dalvik".equals(System.getProperty("java.vm.name"))
        ? new Android() //
        : new Platform(true);
  }
}
Copy the code
3, loadServiceMethod (..)

1.1 loadServiceMethod() The loadServiceMethod function returns ServiceMethod
, takes a Method, which is our custom request function in the interface.

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; }Copy the code

1.2 ServiceMethod. ParseAnnotations (…). Annotations(This, method) A ServiceMethod object is created using the. ParseAnnotations (this, method) method, and then put into a map cache. By the following code, you can see that after a series of abnormal judgment, performs to return HttpServiceMethod. ParseAnnotations (retrofit method, requestFactory) this line of code, we check the code

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

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

1.3 HttpServiceMethod. ParseAnnotations (..) This code is quite long, and I cut some exception judgments and support for the Kotlin Suspend Function. There are a number of important things in this code:

  • Obtain the method’s Annotation[] annotations
  • To obtain the method return value type adapterType = = method. The getGenericReturnType ();
  • CallAdapter

    CallAdapter = createCallAdapter(Retrofit, method, adapterType, Annotations);
    ,>
  • ResponseType = calladapter.responseType ();
  • ResponseConverter = responateresponSeconverter (retrofit, method, responseType);
  • Get an okHttp3.call.factory callFactory = retrofit.callFactory;
  • New (requestFactory, callFactory, responseConverter, callAdapter);

Return new callstuck <>(…)

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> { static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; Annotation[] annotations = method.getAnnotations(); Type adapterType = method.getGenericReturnType(); CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Type responseType = callAdapter.responseType(); Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter); }}Copy the code

1.3 return new CallAdapted < > (…). As you can see, CallCaller inherits HttpServiceMethod and implements the Adapt method.

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> { private final CallAdapter<ResponseT, ReturnT> callAdapter; CallAdapted( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter; } @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) { return callAdapter.adapt(call); }}Copy the code
3,HttpServiceMethod —> invoke(…)

1.1 You can see that the invoke method creates an object called OkHttpCall() and then executes the adapt() method. But the adapt() method is an abstract class, so it’s time to find out where it works… As you can see from 2.1.3 above, the implementation of Adapt () is in class callset
,>

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> { @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); }Copy the code

1.2 point into will find, another interface method, and to find his implementation…. If you look closely, adapt() is called from a callAdapter passed in by the Callstuck () constructor. As you can see from 2.1.2 and 2.1.3, CallAdapter

callAdapter = createCallAdapter(retrofit, method, adapterType, Annotations), so look at createCallAdapter()
,>

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
    private final CallAdapter<ResponseT, ReturnT> callAdapter;

    CallAdapted(
        RequestFactory requestFactory,
        okhttp3.Call.Factory callFactory,
        Converter<ResponseBody, ResponseT> responseConverter,
        CallAdapter<ResponseT, ReturnT> callAdapter) {
      super(requestFactory, callFactory, responseConverter);
      this.callAdapter = callAdapter;
    }

    @Override
    protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
  }
  
  public interface CallAdapter<R, T> {
     T adapt(Call<R> call);
  }
Copy the code

1.3 createCallAdapter (…). The createCallAdapter returns the callAdapter from a list of callAdapterFactories. When was the value added to the list

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> { private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter( Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { try { //noinspection unchecked return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { // Wide exception range because factories are user code. throw methodError(method, e, "Unable to create call adapter for %s", returnType); }}}Copy the code
public final class Retrofit { public CallAdapter<? ,? > callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null, returnType, annotations); } public CallAdapter<? ,? > nextCallAdapter( @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<? ,? > adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter ! = null) { return adapter; }}}}Copy the code

1.4 in the Retrofit. In Java, global search, will find that is in the Retrofit build the add, by callAdapterFactories. AddAll () method, insert values into the callAdapterFactorie collection, Then you should see platform. DefaultCallAdapterFactories (callbackExecutor) is what

 public Retrofit build() {

        okhttp3.Call.Factory callFactory = this.callFactory;
        if (callFactory == null) {
            callFactory = new OkHttpClient();
        }

        Executor callbackExecutor = this.callbackExecutor;
        if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
        }
        // 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));

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

1.5 platform. DefaultCallAdapterFactories (callbackExecutor) first take a look at the incoming callbackExecutor is, the following code

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }
Copy the code

The implementation of platform is an Android() object. The implementation of Platform is an Android() object. The implementation of Platform is an Android() object. Know what callbackExecutor parameters, and then continue to see defaultCallAdapterFactories

static final class Android extends Platform { @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } static final class MainThreadExecutor implements Executor { private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); }}}Copy the code

Ignore the hasJava8Types judgment, it is support for Java8, to see the content in the else directly, is the conversion DefaultCallAdapterFactory object to return a list.

  List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
      @Nullable Executor callbackExecutor) {
    DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
    return hasJava8Types
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
  }

Copy the code

After the process above, can be found in callAdapterFactories callAdapter access to object is DefaultCallAdapterFactory, So adapt () method of implementation should be in DefaultCallAdapterFactory, concrete is, let’s go to see the source code. Click on the

4, DefaultCallAdapterFactory

Adapt () implements the Adapt method in the CallAdapter object, new an ExecutorCallbackCall object, and passes in a Call object and an executor. This executor is known to switch threads, so what is the Call object? “, and we see the familiar Enqueue method in class ExecutorCallbackCall. How does this work? To answer this question, we need to look at what is this Call object

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override
  public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException(
          "Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    final Executor executor =
        Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
            ? null
            : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override
      public Type responseType() {
        return responseType;
      }

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

  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @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()) {
                      // Emulate OkHttp's behavior of throwing/delivering an IOException on
                      // cancellation.
                      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));
            }
          });
    }

    @Override
    public boolean isExecuted() {
      return delegate.isExecuted();
    }

    @Override
    public Response<T> execute() throws IOException {
      return delegate.execute();
    }
  }
}
Copy the code

The Call object is an OkHttpCall() object, and the Call parameter passed to ExecutorCallbackCall is OkHttpCall 1.3. 2 and 3 summarize a chain of method calls like this: invoke[Proxy.newProxyInstance] –> loadServiceMethod(method).invoke(args)[Proxy.newProxyInstance] –> invoke(Object[] args)[HttpServiceMethod] –> adapt(call, Args)[HttpServiceMethod] –> return Calladapter. adapt(call) The return value of the adapt is an ExecutorCallbackCall 1.4 call = apiService.queryData(“ddd”); call.enqueue(..) From 4.1.3, you can execute the Enqueue method from ExecutorCallbackCall, Delegate = OkHttpCall(), the delegate.enqueue method executes the enqueue method in OkHttpCall(), returns the network request’s response, and then switches the thread through the executor passed in. The values are eventually returned to onResponse and onFailure in call.enqueue()

static final class ExecutorCallbackCall<T> implements Call<T> { final Executor callbackExecutor; final Call<T> delegate; ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; } @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()) { // Emulate OkHttp's behavior of throwing/delivering an IOException on // cancellation. 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)); }}); }}Copy the code

At this point, we have formed a logical loop of calls from call.enqueue() sending the request to get the return values onResponse and onFailure, Now it’s time to see what enqueue does in OkHttpCall(). We create a Call object through createRawCall and execute the call object’s enqueue method. What is this call object

5 OkHttpCall
public void enqueue(final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null"); okhttp3.Call call; call = rawCall = createRawCall(); call.enqueue( new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; response = parseResponse(rawResponse); callback.onResponse(OkHttpCall.this, response); } @Override public void onFailure(okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure(Throwable e) { callback.onFailure(OkHttpCall.this, e); }}); }Copy the code

After a series of source searches (check the source code for yourself if you are interested), you can find that the callFactory is an OkHttpClient object belonging to okHttp created during Retrofit build. NewCall is a Call object returned by the OkHttpClient object when newCall is executed. This is associated with the okHttp network access framework. The last call is okHttp’s network access method

  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;
  }
Copy the code

Finally, the source flow for Retrofit is pretty much there, which can be a bit tricky to read because many parameters are initialized when Retrofit is created, and many methods are implemented by subclassing or implementing interfaces. So it is very important to take notes, this article as I read the source notes, there are mistakes, trouble you see more advice