Retrofit源码分析及理解

参考文档:

12W字;2022最新Android11位大厂面试专题(一) - 掘金

Retrofit 版本号:2.9.0

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

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

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

一.使用方法

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

先看看使用方法吧:

使用示例中的接口来自玩Android - wanandroid.com - 每日推荐优质文章

1.添加Retrofit依赖

implementation("com.squareup.retrofit2:retrofit:2.9.0")
// retrofit gson转换器
implementation("com.squareup.retrofit2:converter-gson:2.9.0")

2.创建一个接口

用于管理不同的网络请求

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

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动态代理方式。

// 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进行网络请求。

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

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天免费试用期,之后使用需要付费。

可以参考插件作者的这篇文章了解:Retrofit的好基友-RetrofitAssistant插件 - 掘金

二.为什么好用

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使用建造者模式创建:

val retrofit = Retrofit
    .Builder()
    ...
    .build()

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

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的创建工作:

    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

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

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

val service = retrofit.create(MainService::class.java)
  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偷梁换柱的动作,将注解(菜单)转化成各种对象(菜品),并分配主厨上场。

  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,放入缓存,并返回。

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

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有哪些成员变量:

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,这里对方法的注解、入参、入参注解进行了解析。

    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进行创建:

    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进行处理。这又是一个巧妙使用设计模式的地方,这里用到责任链模式和策略模式。

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

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

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

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

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

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

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

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的一个子类。

  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一调用,主厨开始进行最后的部署工作,并分配了一个部署指挥官。主厨将三个帮手的指挥权传递给部署指挥官,交由他完成下一步工作。

@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:

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

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

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,助你轻松应对英文注释。

  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值