SoFunction
Updated on 2025-03-11

Retrofit source code conversion notes for request objects

BeforeA preliminary study on Retrofit source codeIn this article, we ask three questions:

  1. When will the parameters in the annotation be assembled into http request information?
  2. How to generate an object that initiates the http request?
  3. How to convert an object to the return value we specify in the interface?

The first two questions have been answered in the previous articles. Today we will explore the last question:

When we define an interface, there is something like this:

@GET("hello/world")
Call<News> getNews(@Query("num") String num,@Query("page")String page);

There are also such things:

@GET("book/search")
 Observable<Book> getSearchBook(@Query("q") String name,
                  @Query("tag") String tag, @Query("start") int start,
                  @Query("count") int count);

You can see that the return value of the interface is different. Now let’s analyze how an OkHttpCall object is converted into the corresponding return value.

The core code is this:

return (okHttpCall);

Go to adapt:

T adapt(Call<R> call) {
  return (call);
 }

You can see that the method is called. The callAdapter here is an interface type, so if you want to see the specific implementation of its adapt method, you have to see how the callAdapter is generated.

After searching, it was found that it was generated as follows:

 ServiceMethod(Builder<R, T> builder) {
   //………………
   = ;
   //………………
  }

And this constructor is called in the build method:

 public ServiceMethod build() {
   callAdapter = createCallAdapter();
   //…………
   return new ServiceMethod<>(this);
   }

So continue to follow createCallAdapter():

 private CallAdapter<T, R> createCallAdapter() {
   Type returnType = ();
   if ((returnType)) {
    throw methodError(
      "Method return type must not include a type variable or wildcard: %s", returnType);
   }
   if (returnType == ) {
    throw methodError("Service methods cannot return void.");
   }
   Annotation[] annotations = ();
   try {
    //noinspection unchecked
    return (CallAdapter<T, R>) (returnType, annotations);
   } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(e, "Unable to create call adapter for %s", returnType);
   }
  }

As you can see, the main function here is to obtain method-level annotations and return values, and then pass them into the middle to get the real CallAdapter, so continue to follow:

 public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
 }

Continue to nextCallAdapter:

public CallAdapter&lt;?, ?&gt; nextCallAdapter(@Nullable  skipPast, Type returnType,
   Annotation[] annotations) {
  checkNotNull(returnType, "returnType == null");
  checkNotNull(annotations, "annotations == null");

  int start = (skipPast) + 1;
  for (int i = start, count = (); i &lt; count; i++) {
   CallAdapter&lt;?, ?&gt; adapter = (i).get(returnType, annotations, this);
   if (adapter != null) {
    return adapter;
   }
  }
  //Omit some unimportant code }

This is mainly to iterate through all CallAdapters of Retrofit, and then find the direct return that can handle the return type and method annotations.
For the default return type processing CallAdapter, it is actually added by default when Retrofit is generated:

 public Retrofit build() {
   //Omit some code   Executor callbackExecutor = ;
   if (callbackExecutor == null) {
    callbackExecutor = ();
   }

   // Make a defensive copy of the adapters and add the default Call adapter.
   List&lt;&gt; callAdapterFactories = new ArrayList&lt;&gt;();   
   ((callbackExecutor));
   //Omit some code   return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
     unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
 }

Here is one thing to be said in advance. All CalllAdapter objects are actually generated by calling the get() method of the object.
So here we use() to generate a corresponding object, but first generate a callbackExecutor to generate this object. Let's take a look at what's going on:

@Nullable Executor defaultCallbackExecutor() {
  return null;
 }

Hey, why did it return null? Don't panic, the platform in Retrofit's build will be different subclasses depending on different situations. It is not necessarily an instance of Platform, but its subclass:

 static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
   return new MainThreadExecutor();
  }

  @Override  defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
   if (callbackExecutor == null) throw new AssertionError();
   return new ExecutorCallAdapterFactory(callbackExecutor);
  }

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

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

We focus on the Android platform. You can see that the callbackExecutor executed() method generated here is mainly used to send operations to the main thread for execution.

OK, callbackExecutor we have figured out, so let's continue to see what kind of object the() method generates:

  defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
  if (callbackExecutor != null) {
   return new ExecutorCallAdapterFactory(callbackExecutor);
  }
  return ;
 }

For the Android platform, we generated a corresponding callbackExecutor, so we continued to follow up the statement in if and found that we finally generated an ExecutorCallAdapterFactory() object. Of course, we mainly look at what kind of CallAdapter object can be obtained by its get() method:

 @Override
 public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
  if (getRawType(returnType) != ) {
   return null;
  }
  final Type responseType = (returnType);
  return new CallAdapter<Object, Call<?>>() {
   @Override public Type responseType() {
    return responseType;
   }

   @Override public Call<Object> adapt(Call<Object> call) {
    return new ExecutorCallbackCall<>(callbackExecutor, call);
   }
  };
 }

This get() method generates an anonymous CallAdapter object, so:

(okHttpCall) In the end, it is to call the adapt method of this anonymous object

You can see that the adapt method ultimately converts the OkHttpCall object into an ExecutorCallbackCall object. So what can this object do?

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

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

  @Override public void enqueue(final Callback<T> callback) {
   checkNotNull(callback, "callback == null");

   (new Callback<T>() {
    @Override public void onResponse(Call<T> call, final Response<T> response) {
     (new Runnable() {
      @Override public void run() {
       if (()) {
        // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
        (, new IOException("Canceled"));
       } else {
        (, response);
       }
      }
     });
    }

    @Override public void onFailure(Call<T> call, final Throwable t) {
     (new Runnable() {
      @Override public void run() {
       (, t);
      }
     });
    }
   });
  }

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

  @Override public Response<T> execute() throws IOException {
   return ();
  }

  @Override public void cancel() {
   ();
  }

  @Override public boolean isCanceled() {
   return ();
  }

  @SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
  @Override public Call<T> clone() {
   return new ExecutorCallbackCall<>(callbackExecutor, ());
  }

  @Override public Request request() {
   return ();
  }
 }

It can be clearly seen that this method is a wrapper of the OkHttpCall object. The difference is that its enque() method is rewritten. The purpose of rewriting is very simple, which is to hand over the asynchronous result to MainThreadExecutor and finally convert it to the main thread to execute the callback.

Summarize

The above source code has analyzed a lot, which is a bit messy. Here we will summarize the conversion process of OkHttpCall to the return type defined by the interface (here we take Call<ResponseBody> as an example,):

  1. Generate an Executor object through platform (which is its subclass Android on the Android platform), and the MainThreadExecutor object on Android.
  2. Generate a CallAdapterFactory object through platform, which is the ExecutorCallAdapterFactory object on Android. This object can generate a CallAdapter object through the get() method to convert the OkHttpCall object into an ExecutorCallbackCall object.
  3. The CallAdapterFactory object mentioned above is stuffed into the Retrofit object, and finally called in the adapt() method of the ServiceMethod, convert OkHttpCall into ExecutorCallback, and then you can call the enque() method normally to initiate the request.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.