Retrofit源码分析及理解

参考文档:

juejin.cn/post/714620...

Retrofit 版本号:2.9.0

Retrofit简单来说,就是对OkHttp上层进行了封装,已达到用户方便使用管理网络请求的目的。

Retrofit内部有着简捷、优雅的结构设计。当然对于新手来说,Retrofit也有着不宜理解和上手的问题。不过瑕不掩瑜,Retrofit仍然是一款优秀的网络请求框架。

这边文章除了进行源码分析,还有个人对Retrofit的一些浅见和感悟。仅供读者参考。

一.使用方法

早期网络请求方式,一般都是设计一个OKHttpUtil之类的工具类,实现对Okhttp请求的封装,入参传入url、请求参数param,回调函数callback。这样的请求方式对新用户来说是非常易于上手和容易理解的,但为什么还要使用Retrofit呢,它到底能给我们带来什么呢?

先看看使用方法吧:

使用示例中的接口来自www.wanandroid.com/

1.添加Retrofit依赖

scss 复制代码
implementation("com.squareup.retrofit2:retrofit:2.9.0")
// retrofit gson转换器
implementation("com.squareup.retrofit2:converter-gson:2.9.0")

2.创建一个接口

用于管理不同的网络请求

这里第一个接口返回的类型为Call,此处的Call为Retrofit中的接口,并非Okhttp中的Call(虽然他们接口中定义的方法很类似),如果不特别说明,后面源码分析中的也是这个Call。

less 复制代码
interface MainService {
    @GET("article/list/{index}/json")
    fun paperList(@Path("index") index: Int): Call<MainPaperList>

    @GET("hotkey/json")
    suspend fun hotkey(): HotKey

    @POST("hotkey/json")
    suspend fun hotkey2(@Body req: TestReq): HotKey
}

3.创建Retrofit并创建接口实现的实例

创建Retrofit,完成配置。

这里的接口实现使用Java动态代理方式。

scss 复制代码
// 1.Retrofit创建
val retrofit = Retrofit
    .Builder()
    .baseUrl("https://www.wanandroid.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()

// 2.创建网络请求接口示例
val service = retrofit.create(MainService::class.java)

4.发起请求

这里给出异步请求的示例,默认情况下回调函数会在主线程运行。

动态代理实现中,对调用接口方法进行解析,包括接口参数、返回值和注解,根据这些配置项使用OKHttp进行网络请求。

这里使用反射方式进行解析,可能会稍有耗时,但解析完成后会放在缓存中,再次请求时从缓存中取用。

kotlin 复制代码
fun queryPaperList() {
    service.paperList(0)
        .enqueue(object : Callback<MainPaperList> {
            override fun onResponse(
                call: Call<MainPaperList>,
                response: Response<MainPaperList>
                    ) {
                // 请求成功
            }

            override fun onFailure(call: Call<MainPaperList>, t: Throwable) {
                // 请求异常
            }
        })
}

5.推荐个IDEA插件

在IDEA插件搜索框搜索Retrofit就可以出来。

1.RestfulTool Retrofit

这个插件可以浏览并快速定位到自己定义的Retrofit接口。免费使用。

2.Retrofit Assistant

这个插件功能强大,方便用户快速创建和浏览网络请求的定义的接口,有30天免费试用期,之后使用需要付费。

可以参考插件作者的这篇文章了解:juejin.cn/post/729416...

二.为什么好用

Retrofit有以下优点,分开来解读

1.写法简洁

用接口进行网络请求管理对于初学者来说确实比较怪异,有一定学习曲线,需要花时间来熟悉用法和实现原理。但这样的写法非常简洁方便,声明式的方式定义和处理网络请求可以减少了样板代码的编写。

2.主流支持

同时Retrofit内部实现了对RxJava和协程(2.6.0版本之后)的支持,以及对Json、xml数据格式的支持。这些支持方式免去了使用者去费劲编写转换代码。

3.可扩展

如果需要对请求数据和返回数据做一些转换或者特殊处理,Retrofit同样提供了入口允许用户进行一些特殊处理,比如设置自己的okhttpClient;如需对请求数据和返回数据做一些转换或者特殊处理,可以设置自定义的converterFactory;还可以配置callAdapterFactory,实现特殊的请求方式。

Retrofit存在着大量的设计模式,这些设计模式实现了代码的解耦课可拓展性,这里配置中出现converterFactory和callAdapterFactory都是工厂方法模式的使用。有一些经验的开发者觉得阅读起来会觉得很舒服,而初学者则会有一定的阅读困难。不过很多设计模式都会有这样的问题。设计模式已经广泛应用在各个开源组件的代码中,学习和使用设计模式是提高代码理解能力的必备功课吧。

三.结构总览

Retrofit经营着一家高档餐厅,餐厅里共有五个部门。第一个部门是主厨部门,一个主厨只负责一道菜的指挥和监督工作。还有四个部门,分别归四个管家管理,每个管家负责对小厨娘进行招募,每个部门的小厨娘只负责做菜的其中一个环节。

当一道菜品需要制作时,会组建一个厨师团队进行菜品制作的部署工作,这个团队安排一个主厨负责,还有几个小厨娘供主厨指挥,在部署工作进行中还会招募一些其他帮手。

几个个小厨娘各司其职,互相配合,在主厨指挥下,完成任务,厨师负责最后摆盘,供客人食用。

四个 管家:callFactory、converterFactories、callAdapterFactories、callbackExecutor

主厨团队:serviceMethodCache

请记住这四个管家,他们将在后面源码中频繁出现。

四.源码分析

源码中关键地方都做了中文注释

1.人员预备:Retrofit和Retrofit.Build

这里主要做基础的建设工作。

Retrofit使用建造者模式创建:

ini 复制代码
val retrofit = Retrofit
    .Builder()
    ...
.build()

先看看Retrofit的内部的成员变量和构造方法:

kotlin 复制代码
public final class Retrofit {
    // 接口缓存。一个接口请求的方法为一个Method,对应一个ServiceMethod,ServiceMethod内部有着网络请求相关配置
    private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();

    // OkHttp的接口,创建Okhttp请求(Call)的工厂接口,只有一个实现类:OkHttpClient
    final okhttp3.Call.Factory callFactory;
    // 网络请求基地址,即host地址
    final HttpUrl baseUrl;
    // 将请求或者返回结果进行转换的工厂类列表,比如Retrofit提供的GsonConverterFactory提供了将出入参和Gson进行转换的Converter
    final List<Converter.Factory> converterFactories;
    // callAdapter工厂集合,CallAdapter就是Call的转换器(Retrofit中的Call),callAdapterFactory会根据自己的能力返回合适的CallAdapter
    final List<CallAdapter.Factory> callAdapterFactories;
    // Call请求的回调方法运行的executor,默认Retrofit定义的MainThreadExecutor,即运行在主线程的Executor
    final @Nullable Executor callbackExecutor;
    // 字面意思就是提前验证,如果是true的话,当retrofit.create创建接口实现类时,就进行接口的解析和初始化,生成相应的ServiceMethod,放入缓存map中
    final boolean validateEagerly;

    Retrofit(
        okhttp3.Call.Factory callFactory,
        HttpUrl baseUrl,
        List<Converter.Factory> converterFactories,
        List<CallAdapter.Factory> callAdapterFactories,
        @Nullable Executor callbackExecutor,
        boolean validateEagerly) {
        this.callFactory = callFactory;
        this.baseUrl = baseUrl;
        this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
        this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
        this.callbackExecutor = callbackExecutor;
        this.validateEagerly = validateEagerly;
    }
}

Retrofit.Builder中的成员变量除了多了一个Platform,其他与Retrofit的那些一样,Builder里的方法也是对这些值得设置。

这里的Platform要重点说明一下

Platform提供了对Android和Java平台的支持,也就是说Retrofit不仅可以用在Android开发,还可以用于后端Java开发。

Platform具体提供了以下内容:

1.默认的CallAdapterFactory。 通过defaultCallAdapterFactories方法,其中有DefaultCallAdapterFactory(将异步请求结果的回调使用callbackExecutor运行)、CompletableFutureCallAdapterFactory.INSTANCE(将Call转换为CompletableFuture)。

2.默认的ConverterFactory。 通过defaultConverterFactories方法,只有OptionalConverterFactory.INSTANCE(将结果转换成Optional)。

3.默认的callbackExecutor。 通过defaultCallbackExecutor,这里只有Android平台会提供一个MainThreadExecutor。

我们只分析Android平台。可以认为,Platform提供了Builder进行初始化时四个管家其中三个的默认配置,即converterFactories、callAdapterFactories、callbackExecutor的默认配置(CompletableFutureCallAdapterFactory和OptionalConverterFactory基本上是用不上,此处忽略)。

看看Builder的build方法,是如何完成Retrofit的创建工作:

csharp 复制代码
public Retrofit build() {
    if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
    }

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

    // Make a defensive copy of the converters.
    List<Converter.Factory> converterFactories =
    new ArrayList<>(
        1 + this.converterFactories.size() + platform.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());

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

build方法非常清晰,将Platform提供的用户的配置和Platform提供的默认支持加入,完成Retrofit的创建。

如果没有设置callFactory,那么久创建一个OkHttpClient对象。BuiltInConverters提供了对接口返回值为Void、Unit的支持,以及对注解为Streaming的支持。

2.报菜员就位:Retrofit.create

这一部分是接口实例化工作。

这里分析下面这行代码的源码

ini 复制代码
val service = retrofit.create(MainService::class.java)
typescript 复制代码
  public <T> T create(final Class<T> service) {
    // 如果validateEagerly为true,这里直接对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 {
                // 如果是Object的方法,则直接调用这个方法。这里限制只能是接口
                // If the method is a method from Object then defer to normal invocation.
                if (method.getDeclaringClass() == Object.class) {
                  return method.invoke(this, args);
                }
                // 如果是接口默认方法,则调用默认方法,如果不是则调用loadServiceMethod(method).invoke
                args = args != null ? args : emptyArgs;
                return platform.isDefaultMethod(method)
                    ? platform.invokeDefaultMethod(method, service, proxy, args)
                    : loadServiceMethod(method).invoke(args);
              }
            });
  }

源码中使用了Java提供的动态代理的方式对接口进行实例化。

这里简单讲一下,当用户使用service这个对象调用接口方法时,会被分发到InvocationHandler,并调用起invoke方法,传入这个方法的method和入参args。

Method是Java反射包中的一个类,通过method,我们可以轻松获取到这个方法的注解和入参,由此便能实现将接口转换成网络请求。这是Retrofit核心,理解了这里,再使用Retrofit,便会觉得豁然开朗。

loadServiceMethod(method).invoke(args) 这句是重点,分开来分析,先loadServiceMethod,再分析invoke(ServiceMethod的方法)。

3.分配主厨:loadServiceMethod

这一步正是Retrofit偷梁换柱的动作,将注解(菜单)转化成各种对象(菜品),并分配主厨上场。

sql 复制代码
  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;
  }

先从缓存中查找,如果没有便通过ServiceMethod.parseAnnotations(this, method)获取到ServiceMethod,放入缓存,并返回。

java 复制代码
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);
}

首先创建了requestFactory,将requestFactory传递给厨师HttpServiceMethod,然后返回。

有请主厨HttpServiceMethod闪亮登场,只见他左边张小龙(requestFactory),右边赵小虎(responseConverter),前方展小昭(callFactory)。

ini 复制代码
private final RequestFactory requestFactory;
private final okhttp3.Call.Factory callFactory;
private final Converter<ResponseBody, ResponseT> responseConverter;

HttpServiceMethod(
    RequestFactory requestFactory,
    okhttp3.Call.Factory callFactory,
    Converter<ResponseBody, ResponseT> responseConverter) {
    this.requestFactory = requestFactory;
    this.callFactory = callFactory;
    this.responseConverter = responseConverter;
}

在这里,requestFactory成为了主厨的帮手。

下面看看RequestFactory有什么能力来帮助主厨。

先来看看RequestFactory.parseAnnotations方法和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;
  // 相对url,例如注解@GET后面的值
  private final @Nullable String relativeUrl;
  // 注解Headers解析,格式为 Name: Value
  private final @Nullable Headers headers;
  // 注解Header中Content-Type的值
  private final @Nullable MediaType contentType;
  // 是否有body
  private final boolean hasBody;
  // 是否是FormEncoded
  private final boolean isFormEncoded;
  // 是否是Multipart
  private final boolean isMultipart;
  // 方法的每个入参都有一个对应的parameterHandlers
  private final ParameterHandler<?>[] parameterHandlers;
  // 是否是kotlin的suspend方法
  final boolean isKotlinSuspendFunction;

  // 省略以下内容
}

RequestFactory依旧是工厂,但不是抽象工厂,这个工厂是Request工厂,就是创建用来创建okhttp3.Request的工厂。除了创建Request,这里对方法的注解、入参、入参注解进行了解析。

ini 复制代码
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      // 获取方法注解,返回值为Annotation[]
      this.methodAnnotations = method.getAnnotations();
      // 获取方法参数类型,返回值为Type[]
      this.parameterTypes = method.getGenericParameterTypes();
      // 获取参数中的注解,返回值为Annotation[][]
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

这里的parseAnnotations,依旧是建造者模式来创建。

Builder.build方法对RequestFactory进行创建:

ini 复制代码
    RequestFactory build() {
      // 解析方法注解,例如GET、POST、HTTP、Multipart、FormUrlEncoded等等
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      // 略过错误检查代码...

      // 解析每个入参和其注解,生成对应的ParameterHandler
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
        parameterHandlers[p] =
            parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
      }

      // 略过错误检查代码...

      return new RequestFactory(this);
    }

说一下这里的ParameterHandler,下方是ParameterHandler的源码,这是是一个用于处理请求参数的抽象类,内部只有一个抽象方法apply。在后面创建Request请求时(RequestBuilder),按顺序执行ParameterHandler列表中每个ParameterHandler的apply方法,对RequestBuilder进行处理。这又是一个巧妙使用设计模式的地方,这里用到责任链模式和策略模式。

less 复制代码
abstract class ParameterHandler<T> {
  abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
  // 忽略其他
}

责任链模式:ParameterHandler的实现类可以形成一个责任链,每个处理器负责处理特定类型的参数,如果当前处理器无法处理参数,则将参数传递给下一个处理器。这样可以很好地组织和管理参数的处理流程。

策略模式:ParameterHandler可以根据不同的参数类型采用不同的处理策略,每个实现类都代表一种具体的处理策略,通过接口的多态性可以灵活地切换处理策略。

这种设计模式使得Retrofit可以动态地处理各种类型的请求参数,并且方便扩展和维护。

RequestFactory源码中可以看到久违的Retrofit的注解,这里开始完成对注解和参数的解析。如果对这些注解处理感兴趣,可以看这个类。

我们再来分析分析HttpServiceMethod的parseAnnotations方法。

HttpServiceMethod的parseAnnotations方法,从名字可以看出,仍然是对注解的解析

ini 复制代码
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
    Retrofit retrofit, Method method, RequestFactory requestFactory) {
    boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
    boolean continuationWantsResponse = false;
    boolean continuationBodyNullable = false;

    Annotation[] annotations = method.getAnnotations();
    Type adapterType;
    if (isKotlinSuspendFunction) {
        // ...
        //  暂时不分析对kotlin挂起函数的支持
    } else {
        adapterType = method.getGenericReturnType();
    }

    // 从callAdapterFactories中获取到合适的CallAdapter,对Call进行转换
    CallAdapter<ResponseT, ReturnT> callAdapter =
    createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();

    // 忽略部分检查错误的代码

    // 从converterFactories中获取到合适的responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =
    createResponseConverter(retrofit, method, responseType);

    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {
        return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else {
        // ...
        // 暂时不分析对kotlin挂起函数的支持
    }
}

暂时不分析kotlin挂起函数,先看普通函数的处理。拿到requestFactory、合适的callAdapter、合适的responseConverter,组成了新的CallAdapted,CallAdapted是HttpServiceMethod的一个子类。

scala 复制代码
  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);
    }
  }

主厨CallAdapted上场了。

loadServiceMethod方法,最终得到的就是这个CallAdapted,它也有着自己的四个厨娘的调用权:requestFactory(功能:对请求的解析和创建)、callFactory(默认就是OkhttpClient)、responseConverter和callAdapter。

4.工作部署:invoke

HttpServiceMethod.invoke一调用,主厨开始进行最后的部署工作,并分配了一个部署指挥官。主厨将三个帮手的指挥权传递给部署指挥官,交由他完成下一步工作。

less 复制代码
@Override
final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
}

invoke方法只有两行,创建一个OkHttpCall对象,执行adapt(call, args)。

先要说明一点,这里的OkHttpCall是Retrofit包中的一个类,并不是OkHttp包中的,但这个类封装了对OKHttp中Call请求的创建和处理。

看看OkHttpCall的构造函数和它的成员变量,有requestFactory、callFactory,、responseConverter,通过这几个,它的能力便可以想象得到。

再回到adapter方法的分析,loadServiceMethod返回的CallAdapted对adapt进行了重写,返回了callAdapter.adapt(call)。

来看看默认的CallAdapterFactory和其提供的Adapter:

kotlin 复制代码
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
    @Nullable
    private final Executor callbackExecutor;

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

    @Nullable
    public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
            return null;
        } else if (!(returnType instanceof ParameterizedType)) {
            throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
        } else {
            // 如果没有使用SkipCallbackExecutor注解,那就返回ExecutorCallbackCall
            final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
            final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
            return new CallAdapter<Object, Call<?>>() {
                public Type responseType() {
                    return responseType;
                }

                public Call<Object> adapt(Call<Object> call) {
                    return (Call)(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;
        }

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

                    });
                }

                public void onFailure(Call<T> call, Throwable t) {
                    ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
                        callback.onFailure(ExecutorCallbackCall.this, t);
                    });
                }
            });
        }

        public boolean isExecuted() {
            return this.delegate.isExecuted();
        }

        public Response<T> execute() throws IOException {
            return this.delegate.execute();
        }

        public void cancel() {
            this.delegate.cancel();
        }

        public boolean isCanceled() {
            return this.delegate.isCanceled();
        }

        public Call<T> clone() {
            return new ExecutorCallbackCall(this.callbackExecutor, this.delegate.clone());
        }

        public Request request() {
            return this.delegate.request();
        }

        public Timeout timeout() {
            return this.delegate.timeout();
        }
    }
}

这里返回了ExecutorCallbackCall,对传入的OkHttpCall对象做了一层简单的封装,enqueue方法将回调函数运行在主线程中。可以认为这里使用了代理模式。

这里简单理解为部署完成,最后部署指挥官便是ExecutorCallbackCall。

5.做菜了:enqueue

当用户要菜时(发起请求时),部署指挥官开始指挥工作,稍后便将美食制作完成:

kotlin 复制代码
service.paperList(0)
.enqueue(object : Callback<MainPaperList> {
    override fun onResponse(
        call: Call<MainPaperList>,
        response: Response<MainPaperList>
    ) {
        // 请求成功
    }

    override fun onFailure(call: Call<MainPaperList>, t: Throwable) {
        // 请求异常
    }
})

部署指挥官的工作就是指挥,底层工作仍是别人执行:

分析便止于此。

我想以容易理解的方式进行源码解读,但是我给出的一个餐厅模型对于源码中部分逻辑仍然难以适配,因此只做入门理解使用。

因为能力有限,以上分析会有部分理解错误之处,希望各位提出。

五.总结

Retrofit作为一个轻量的网络请求封装库,却有着丰富和优雅的设计。这是非常值得大家分析学习的。

在分析源码的过程中,下面几点会更好地帮助到你:

1.理解类名

优秀的框架通过类名便可以看出这个类功能的一二。

比如XXFactory,一般都是工厂模式,对应会有一个create方法区创建一个XX。

XXAdapter和XXConvert,名字更是直接表明是一个适配器或者转换类。

2.看看类的成员变量,判断类的能力

面向对象的一大特征便是封装。类的成员变量,便是类所封装和承载的信息。对于不熟悉的类,不妨先看看他的成员变量有哪些,看看他有什么能力。

3.阅读注释

有时候看注释也会不理解,但不妨碍注释给我的启示作用。

推荐一个免费的IDEA插件Translation,助你轻松应对英文注释。

相关推荐
Aileen_0v01 小时前
【玩转OCR | 腾讯云智能结构化OCR在图像增强与发票识别中的应用实践】
android·java·人工智能·云计算·ocr·腾讯云·玩转腾讯云ocr
江上清风山间明月4 小时前
Flutter DragTarget拖拽控件详解
android·flutter·ios·拖拽·dragtarget
debug_cat7 小时前
AndroidStudio Ladybug中编译完成apk之后定制名字kts复制到指定目录
android·android studio
编程洪同学11 小时前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
氤氲息13 小时前
Android 底部tab,使用recycleview实现
android
Clockwiseee13 小时前
PHP之伪协议
android·开发语言·php
小林爱14 小时前
【Compose multiplatform教程08】【组件】Text组件
android·java·前端·ui·前端框架·kotlin·android studio
小何开发15 小时前
Android Studio 安装教程
android·ide·android studio
开发者阿伟15 小时前
Android Jetpack LiveData源码解析
android·android jetpack
weixin_4381509915 小时前
广州大彩串口屏安卓/linux触摸屏四路CVBS输入实现同时显示!
android·单片机