Android network programming (12) Retrofit2 principle analysis

1 Usage review

We have already introduced the use of Retrofit in the previous blog post "Use of Retrofit2 Framework for Android Network Programming (11)" . Today we continue to read the key source code of Retrofit so that it can have a deeper understanding. Before we start, let ’s review the simple use, and use the steps to analyze the principles behind each line of code in depth, such as:

    // 0 创建一个网络请求的接口
    public interface AppInfoService {
        @GET("url.json")
        Call<List<AppInfo>> getAppInfoList(@Query("id") int id);
    }

    private void getRequest() {
        // 1 创建 Retrofit 对象,输入请求URL、转换器等
        Retrofit retorfit = new Retrofit.Builder()
                .baseUrl("https://api.xx.com/ ")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2 通过Retrofit的create创建自定义的请求接口对象
        AppInfoService appInfoService = retorfit.create(AppInfoService.class);
        // 3 通过调用请求接口方法创建Call对象
        Call<List<AppInfo>> call = appInfoService.getAppInfoList(123);
        // 4 发起同步或异步的网络请求
//        try {
//            Response<List<AppInfo>> response = call.execute();
//            List<AppInfo> appInfos = response.body();
//            Log.e("zyx", appInfos.toString());
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        call.enqueue(new Callback<List<AppInfo>>() {
            @Override
            public void onResponse(Call<List<AppInfo>> call, Response<List<AppInfo>> response) {
                List<AppInfo> appInfos = response.body();
                Log.e("zyx", appInfos.toString());
            }

            @Override
            public void onFailure(Call<List<AppInfo>> call, Throwable t) {
                Log.e("zyx", t.toString());
            }
        });
    }

It can be seen that the steps are probably:

0 Create a custom network request interface, which contains the incoming method of request method, request server interface name and request parameters;

1 Create a Retrofit object, enter the request URL, converter, etc .;

2 Create a custom request interface object through Retrofit create;

3 Create a Call object by calling the request interface method;

4 Initiate synchronous or asynchronous network requests.

2 Principle analysis

2.1 Create Retrofit object

The process of creating Retrofit objects is also initialized using the constructor pattern. First, the Builder method will eventually call the findPlatform method of the Platform class.

Retrofit.java

public static final class Builder {
  // ……
  Builder(Platform platform) {
    this.platform = platform;
  }

  public Builder() {
    this(Platform.get());
  }
}

Platform.java

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
}

As can be seen from the above code, the findPlatform method will create different Platform objects according to different operating platforms. Then call its build method.

Retrofit.java

public final class Retrofit {
public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    // ……

    public Retrofit build() {
// 关键代码1,判断baseUrl是否为空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      // 关键代码2,获得或创建 网络请求执行器工厂 okhttp3.Call.Factory对象
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 关键代码3,获得或创建回调方法执行器Executor对象
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

// 关键代码4,创建 网络请求适配器工厂CallAdapter.Factory列表,
// 并将callAdapterFactories和上面的callbackExecutor对象创建出默认的defaultCallAdapterFactories添加其中
      // 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));

// 关键代码5,创建 数据转换器工厂Converter.Factory列表
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size() + latform.defaultConverterFactoriesSize());
      // 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());
      // 关键代码6,实例化Retrofit对象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  }
}

The logic in the Build method is very clear, mainly 5 things:

  1. To determine whether baseurl is empty, the value of baseurl is set by .baseUrl method.
  2. Obtaining the network a request to perform factory callFactory object value, if it is empty, then the object is to create a OkHttpClient, so obviously Retrofit OkHttp default network request, callFactory values by . Client method is provided.
  3. Obtain the callbackExecutor object value of the callback method executor. If it is empty, create a default. The default is a MainThreadExecutor object and it has a Handler with Looper inside. We will discuss it later. The value of callbackExecutor can be set by the callbackExecutor method.
  4. Obtain the value of the network request adapter factory callAdapterFactories and add it to the list. The value of callAdapterFactories can be set by the .addCallAdapterFactory method. After the list is created, add the callbackExecutor object in key code 3 to it.
  5. Create a list of data converter factories Converter.Factory, and then add the built-in data converter BuiltInConverters and the default data converter factory defaultConverterFactories, which also get the value of converterFactories, also add it to the list, the value of converterFactories can be passed. AddConverterFactory Method to add.
  6. Finally, pass the above object into the Retrofit constructor to instantiate the Retrofit object. Note that the value of validateEagerly means that it is verified in advance, which can be set by the .validateEagerly method.

2.2 Create a custom request interface object through Retrofit create

For example, the code AppInfoService appInfoService = retorfit.create (AppInfoService.class) ;, Retrofit's create method is a generic method, the parameter is a custom interface type, the return value is a Proxy.newProxyInstance dynamic proxy object, please see the code .

Retrofit.java

public final class Retrofit {
  // ……
  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
// 关键代码1,是否提前验证
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
// 关键代码2,创建一个用于网络请求接口的动态代理对象并返回 
    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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
// 关键代码3,加载网络请求接口里的方法,并执行
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
      }
    }
  }
  // ……
}
  1. The create method will first determine whether the validateEagerly variable is true, that is, whether it is validated in advance. The eagerlyValidateMethods method is actually to trigger the loadServiceMethod method logic in key code 3 in advance.
  2. At key code 2, here is to create a dynamic proxy object for the network request interface, that is, when we call the getAppInfoList method using AppInfoService in the callback example, the invoke method of the InvocationHandler will eventually be called.
  3. The key code 3 is to load and execute the method in the interface of the network request. The method is our custom getAppInfoList method.

2.3 Create a Call object by calling the request interface method

For example, the code Call <List <AppInfo >> call = appInfoService.getAppInfoList (123); in this example, this method returns a Call object. From 2.2, we know that this method will eventually be called into Retrofit's loadServiceMethod method, which returns the object's invoke method. , So we continue to look at the code of the loadServiceMethod method and invoke method.

2.3.1 loadServiceMethod 方法

Retrofit.java

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
  // ……
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;
  }
// ……
}

The loadServiceMethod method first reads from the static Map object serviceMethodCache whether there is a previously created network request instance, and if there is, it returns directly. Otherwise, it is created by the ServiceMethod.parseAnnotations method and then added to the serviceMethodCache to finally return the newly created object.

ServiceMethod.java

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 关键代码1,创建一个请求工厂RequestFactory对象
    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.");
    }

// 关键代码2,创建HttpServiceMethod对象并返回
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

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

The method is to do two things:

  1. Create a request factory through the parseAnnotations method of the RequestFactory class.
  2. Finally create an HttpServiceMethod object and return.

Below we continue to analyze the logic of RequestFactory's parseAnnotations method and HttpServiceMethod's parseAnnotations method.

2.3.1.1 The parseAnnotations method of RequestFactory

RequestFactory.java

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

  private final Method method;
  private final HttpUrl baseUrl;
  final String httpMethod;
  private final @Nullable String relativeUrl;
  private final @Nullable Headers headers;
  private final @Nullable MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  final boolean isKotlinSuspendFunction;

  RequestFactory(Builder builder) {
    method = builder.method;
    baseUrl = builder.retrofit.baseUrl;
    httpMethod = builder.httpMethod;
    relativeUrl = builder.relativeUrl;
    headers = builder.headers;
    contentType = builder.contentType;
    hasBody = builder.hasBody;
    isFormEncoded = builder.isFormEncoded;
    isMultipart = builder.isMultipart;
    parameterHandlers = builder.parameterHandlers;
    isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
  }
// ……
  static final class Builder {
    // ……
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    RequestFactory build() {
      // ……
      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;
    }
  }
// ……
}

It can be seen that the parseAnnotations method of RequestFactory is actually passed in Retrofit objects and method parameters, and then by reading the annotation values ​​defined in the method (parseMethodAnnotation method in the class), an object of various network request parameters is obtained.

2.3.1.2 The parseAnnotations method of HttpServiceMethod

After obtaining the RequestFactory object, it is passed to the parseAnnotations method of HttpServiceMethod as a parameter, and then look at the code.

HttpServiceMethod.java

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // ……
// 关键代码1,从Retrofit对象中的 网络请求适配器工厂 获得 网络请求适配器callAdapter和其请求类型
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
    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.");
    }

// 关键代码2,从Retrofit对象中的 数据转换器工厂 获得 数据转换器 responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =  createResponseConverter(retrofit, method, responseType);

// 关键代码3,从Retrofit对象中的 获得 网络请求执行器工厂 callFactory
    okhttp3.Call.Factory callFactory = retrofit.callFactory;

// 关键代码4,根据类型创建不同的HttpServiceMethod实现
    if (!isKotlinSuspendFunction) {
      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);
    }
  }
  // ……
}

HttpServiceMethod's parseAnnotations method will get the network request adapter callAdapter, data converter responseConverter, network request executor factory callFactory and the request factory RequestFactory passed in the parameters in the Retrofit object as parameters to create three types of It is the HttpServiceMethod object of CallAdapted, SuspendForResponse and SuspendForBody. Among them, SuspendForResponse and SuspendForBody are supported by the Kotlin suspend method, so we just look at CallAdapted.

HttpServiceMethod.java

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

 2.3.2 invoke method

Looking back at the above return loadServiceMethod (method) .invoke (args! = Null? Args: emptyArgs); code, when the loadServiceMethod method returns the ServiceMethod object, then the invoke method is called.

ServiceMethod.java

abstract class ServiceMethod<T> {
  // ……
  abstract @Nullable T invoke(Object[] args);
}

The implementation of the invoke method is in the HttpServiceMethod class.

HttpServiceMethod.java

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

The Invoke method is very simple, which is to call the adapt method, which is the adapt method in the implementation class CallAdapted of HttpServiceMethod. The code has been posted above. Please remember here that the first parameter call is OkHttpCall.

HttpServiceMethod.java

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  //……
  @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

The ultimate is the adapt method of the network request adapter callAdapter.

This network request adapter callAdapter is the network request adapter callAdapter obtained from the network request adapter factory in the Retrofit object in the key code 1 in the parseAnnotations method of the HttpServiceMethod. Looking back at the network request adapter factory created in the Retrofit object above, it was mentioned that the value of the network request adapter factory callAdapterFactories can be set by the .addCallAdapterFactory method and the default defaultCallAdapterFactories

Platform.java

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
  return singletonList(new DefaultCallAdapterFactory(callbackExecutor));
}
DefaultCallAdapterFactory.java
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);
      }
    };
  }
}

Finally, if we don't specify the callAdapter through the .addCallAdapterFactory method, the invoke method will be executed in the DefaultCallAdapterFactory class, so the Call object created is the ExecutorCallbackCall object.

The ExecutorCallbackCall constructor of DefaultCallAdapterFactory receives two parameters. Let me talk about the second parameter call, we can know that it is an OkHttpCall object in the HttpServiceMethod invoke. The first parameter executor is the callback method executor callbackExecutor when the Retrofit object is created . If it is not set by the .callbackExecutor method, it defaults to platform.defaultCallbackExecutor () ;, a MainThreadExecutor object, its source code is as follows, visible There is a Handler with Looper inside.

Platform.java

class Platform {
  // ……
  static class Android extends Platform {
    // ……
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
// ……
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

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

2.4 Initiating a network request

After obtaining the Call object, it is the last to send a network request. From the above, we know that the Call object is DefaultCallAdapterFactory.ExecutorCallbackCall, so whether it is an asynchronous or synchronous request, the enqueue and execute methods in DefaultCallAdapterFactory.ExecutorCallbackCall are called. The source code is as follows.

DefaultCallAdapterFactory.java

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  // ……
  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) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              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(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

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

The enqueue and execute methods both delegate to the delegate object for execution, and the delegate object is the OkHttpCall object. So we only understand the enqueue logic of OkHttpCall.

OkHttpCall.java

final class OkHttpCall<T> implements Call<T> {
  // ……
  @Override public void enqueue(final Callback<T> callback) {
    // ……
    okhttp3.Call call;
    // ……
      if (call == null && failure == null) {
        try {
// 关键代码1,创建okhttp3的call对象
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          // ……
        }
      }
    }
    // ……
// 关键代码2,执行call对象的异常请求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
// 关键代码3,获得请求结果进行解析
          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 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;
  }
}

In key code 1, a call object of okhttp3 is created by the createRawCall method, and then the abnormal request of okhttp3 is executed in key code 2, and then the result of the request is parsed and encapsulated in the key code 3 by the parseResponse method. The final result is then called back into ExecutorCallbackCall, and we know that the callback of okhttp3 is executed in the child thread. In ExecutorCallbackCall is the MainThreadExecutor object, because it has a Looper Handler, so the result is finally called back to the main thread to execute .

In the same way, the synchronous method execute is also the execute method of calling the call object of okhttp3, and finally the parseResponse method is used to parse and encapsulate the request result.

3 Summary

So far, the Retrofit2 framework has been introduced. Although a lot of details are omitted in the process, the overall process principle still understands a lot through the source code. Let us now summarize the principle in short words:

The first one , create Retrofit objects inside the first will be to create different Platform objects according to different operating platforms. Then initialize the parameters through the constructor mode, such as using:

  1. Use the baseUrl method to set the URL to be accessed;
  2. Selectively use the callFactory method to create a " network request executor factory " callFactory. If this method is not used, an OkHttpClient object will be created;
  3. Selectively use the callbackExecutor method to create a " callback method executor " callbackExecutor, if you do not use this method, create a default defaultCallbackExecutor, which is a MainThreadExecutor object with Looper Handler;
  4. Selectively use the addCallAdapterFactory method to add " network request adapter factory ", and append a default network requester DefaultCallAdapterFactory;
  5. Selectively use addConverterFactory method to add " data converter factory ";
  6. Finally, Retrofit is instantiated through the objects created above.

Of 2 , Create Retrofit by a generic method and a custom interface type will be passed to create a custom request interface objects, the object is to use the dynamic proxy object Proxy.newProxyInstance.

The first 3 , create Call object by calling the custom request interface method,

  1. First get the annotation value in the definition method to create a " request factory " RequestFactory, and then get the " network request adapter " callAdapter, " data converter " responseConverter, " network request executor factory " callFactory in the Retrofit object and the newly created The " Request Factory " RequestFactory creates CallAdapted objects inherited from HttpServiceMethod according to the type;
  2. Because the dynamic proxy is used, the adapt method of the CallAdapted object is finally called, and because the default " network request adapter " is the DefaultCallAdapterFactory object, the last Call object created inside the adapt method is the ExecutorCallbackCall object.

The first 4 , initiates a network request is to be executed by the enqueue and asynchronous and synchronous execute the method DefaultCallAdapterFactory.ExecutorCallbackCall. These two methods are completed by an OkHttpCall object, OkHttpCall internally encapsulates the okhttp3 network request. After the request is completed, the result is returned to the ExecutorCallbackCall, and then the result is returned to the caller's main thread through the MainThreadExecutor callback method executor with Looper's Handler.

 

 

 

Published 106 original articles · praised 37 · 80,000 views

Guess you like

Origin blog.csdn.net/lyz_zyx/article/details/103728964