阅读 1747

Android进阶知识:Retrofit相关

1.前言

Retrofit是什么?Retrofit是一个遵循RESTful设计的进行HTTP网络请求框架的封装,是现在Android端最火的进行网络请求的库。就像Volley是谷歌官方对HttpURLConnectionHttpClient的封装,或者像Github上许多开发者发布的对HttpURLConnectionOkHttp封装库一样,Retrofit也是Square公司发布的对OkHttp进行了封装,因此Retrofit中的底层网络请求是由OkHttp来完成的。

2.基础使用

Retrofit的使用步骤很简单,首先是创建一个网络请求接口描述文件。

// 创建一个接口文件ApiService,Retrofit将每个Http接口请求,抽象为接口中的一个方法。
public interface ApiService {
    @GET("api")
    Call<WeatherBean> getWeather(@Query("version") String key, @Query("cityid") String city);
}
复制代码

接着就可以创建Retrofit对象了。

// 创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
        // 设置baseUrl
        .baseUrl("http://www.tianqiapi.com/")
        // 添加响应数据转换器工厂,这里是Gson将获得响应结果转换成Gson对象
        .addConverterFactory(GsonConverterFactory.create())
        // 添加网络请求适配器工厂,这里是RxJava2将Call转换成Rxjava中的Observable
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build();
// 创建接口实例
ApiService service = retrofit.create(ApiService.class);
// 调用接口中方法
Call<WeatherBean> responseCall = service.getWeather("v1", "101110101");
// 发送同步请求
responseCall.execute();
// 发送异步请求
responseCall.enqueue(new Callback<WeatherBean>() {
     @Override
     public void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {
     // 主线程
        String responseStr = response.body().toString();
        Log.e("result", responseStr);
    }

    @Override
    public void onFailure(Call<WeatherBean> call, Throwable t) {
      // 主线程
        Log.e("result", t.getMessage());
    }
});
复制代码

这里稍微注意下这两行:

 // 添加响应数据转换器工厂,这里是Gson将获得响应结果转换成Gson对象
 .addConverterFactory(GsonConverterFactory.create())
 // 添加网络请求适配器工厂,这里是RxJava2将Call转换成Rxjava中的Observable
 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
复制代码

这里的ConverterFactory表示数据转换器工厂,就是将接收到的响应结果数据转换成想要的类型,例如一般使用Gson来解析服务器返回的数据,这里就添加了一个GsonConverterFactoryCallAdapterFactory表示的是网络请求适配器的工厂,它对应的是接口请求方法的返回类型,是将默认的ExecutorCallbackCall转换成适配其它不同平台所需要的类型。例如这里添加了RxJava的适配器,那么接口中就可以写成以下这样,返回一个RxJava中的Observable类型。

 @GET("api")
 Observable<WeatherBean> getWeather(@Query("version") String key, @Query("cityid") String city);
复制代码

3.源码运行流程

本篇文章中的源码皆是基于Retrofit2.6.0版本,下面开始通过看源码来进一步了解Retrofit,当然这里还是按照使用方法的顺序开始。

3.1 创建Retrofit.Builder。

 public Builder() {
      this(Platform.get());
 }
 Builder(Platform platform) {
      this.platform = platform;
 }
复制代码

首先通过Platform.get获得了一个Platform,然后调用重载的构造方法。先来看看Platformget方法,了解下Platform是做什么的。

  private static final Platform PLATFORM = findPlatform();
  // get方法之间返回静态成员变量PLATFORM
  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();
  }
复制代码

get方法中看到直接返回了静态成员变量PLATFORM,而PLATFORM又是通过findPlatform方法获得的,最后在findPlatform方法里看到这个方法是用来做多平台兼容的,根据不同的平台返回不同的Platform,这里有AndroidJava,接下来进一步看看Android平台下的返回的Android这个对象。

  static class Android extends Platform {
    // 判断是否是默认方法:API24之前统一返回false,之后调用Method类中方法判断
    @IgnoreJRERequirement // Guarded by API check.
    @Override boolean isDefaultMethod(Method method) {
      if (Build.VERSION.SDK_INT < 24) {
        return false;
      }
      return method.isDefault();
    }
    // 初始化默认的主线程执行器
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
    // 初始化默认网络请求适配器工厂集合
    @Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
        @Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      DefaultCallAdapterFactory executorFactory = new DefaultCallAdapterFactory(callbackExecutor);
      return Build.VERSION.SDK_INT >= 24
        ? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
        : singletonList(executorFactory);
    }
    // 默认网络请求适配器工厂集合大小
    @Override int defaultCallAdapterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
    }
    // 初始化默认数据转换器工厂集合
    @Override List<? extends Converter.Factory> defaultConverterFactories() {
      return Build.VERSION.SDK_INT >= 24
          ? singletonList(OptionalConverterFactory.INSTANCE)
          : Collections.<Converter.Factory>emptyList();
    }
    // 默认数据转换器工厂集合大小
    @Override int defaultConverterFactoriesSize() {
      return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
    }
	// MainThreadExecutor主线程执行器
    static class MainThreadExecutor implements Executor {
     // 主线程Handler
      private final Handler handler = new Handler(Looper.getMainLooper());
      @Override public void execute(Runnable r) {
        // 将传入的Runnable使用主线程Handler处理
        handler.post(r);
      }
    }
  }
复制代码

大概看一下Android中的方法,主要是初始化Retrofit需要的功能的。defaultCallbackExecutor方法初始化主线程的执行器,默认情况下异步请求结束后通过它来回到主线程。defaultCallAdapterFactories是初始化请求默认转换器工厂集合,默认创建了一个转换器工厂DefaultCallAdapterFactorydefaultConverterFactories是初始化默认数据转换器工厂集合。可以看出Retrofit在这里提供了设置默认的数据转换器工厂和网络请求适配器工厂的方法,默认会调用这些方法设置默认的数据转换器工厂和网络请求适配器工厂。

3.2 设置baseUrl

public Builder baseUrl(String baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      return baseUrl(HttpUrl.get(baseUrl));
}
    
public Builder baseUrl(HttpUrl baseUrl) {
      checkNotNull(baseUrl, "baseUrl == null");
      List<String> pathSegments = baseUrl.pathSegments();
      if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
        throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
      }
      this.baseUrl = baseUrl;
      return this;
}
复制代码

baseUrl方法实现非常简单就是将baseUrl设置到Retrofit.Builder中,参数类型为String的方法将传入的字符串封装成了一个HttpUrl对象,调用对应重载方法,重载方法中调用pathSegments方法将url分割,然后判断url是否是以斜杠结尾,不是则抛出异常。

3.3 添加数据转换器工厂

 private final List<Converter.Factory> converterFactories = new ArrayList<>();

 public Builder addConverterFactory(Converter.Factory factory) {
      converterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
    }
复制代码

该方法就是将传入的数据转换器工厂加入到成员变量中的数据转换器工厂集合中。

3.4 添加网络请求适配器工厂

private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
      callAdapterFactories.add(checkNotNull(factory, "factory == null"));
      return this;
}
复制代码

该方法同样是将传入的网络请求适配器工厂加入到成员变量中的网络请求适配器工厂集合中。

3.5 调用build方法构建Retrofit对象

    public Retrofit build() {
      // 判断baseUrl不为空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
     // 创建callFactory 默认为OkHttpClient
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
    // 获取默认的回调执行器,没有就会调用platform.defaultCallbackExecutor
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // 创建网络请求适配器工厂集合,调用platform.defaultCallAdapterFactories加入默认网络请求适配器工厂
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

      // 创建数据转换器工厂集合
      List<Converter.Factory> converterFactories = new ArrayList<>(
          1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());

      // 添加内置的数据转换器工厂
      converterFactories.add(new BuiltInConverters());
	  // 添加add方法添加的数据转换器工厂
      converterFactories.addAll(this.converterFactories);
	  // 添加默认的数据转换器工厂
      converterFactories.addAll(platform.defaultConverterFactories());
	  // 创建一个Retrofit对象返回
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
复制代码

build方法中就做了许多初始化工作,包括调用了平台适配器Android中看到的那些方法,最终创建了所需的Retrofit对象。具体来看它做了哪些工作。首先是判断了baseUrl是否为空,为空会抛出异常,这也对应了我们在使用Retrofit时必须要设置baseUrl。接着初始化了一个callFactory网络请求工厂,默认的就是OkHttpClient,这也看出了Retrofit默认底层网络请求采用的就是OkHttp框架。然后创建了回调执行器默认会调用之前看过的Platform中的对应方法拿到主线程的执行器。下两步其实差不多,就是创建网络请求适配器工厂集合和数据转换器工厂集合并且添加默认的网络请求适配器工厂数据转换器工厂。最后初始化工作完成后创建一个Retrofit对象返回。这里再看一下Retrofit的成员变量和构造函数。

public final class Retrofit {
  // 一个支持并发的ConcurrentHashMap,存放请求方法的缓存,这里的ServiceMethod是解析请求方法之后的封装
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
  // 网络请求工厂
  final okhttp3.Call.Factory callFactory;
  // baseUrl
  final HttpUrl baseUrl;
  // 数据转换器工厂集合
  final List<Converter.Factory> converterFactories;
  // 网络请求适配器工厂集合
  final List<CallAdapter.Factory> callAdapterFactories;
  // 回调执行器
  final @Nullable Executor callbackExecutor;
  // 是否提前验证解析的标志
  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;
  }
  ......
  }
复制代码

这里看到构造方法中就只是做了初始化赋值操作,再来看看它的成员变量,除了之前看过的那些,这里多了一个ConcurrentHashMap用来缓存ServiceMethod。还有一个validateEagerly布尔值标志,这个标志的作用是判断是否提前验证解析,先大概了解下,具体的在后面的代码里会看到。

3.6 调用Retrofit的create方法创建网络请求接口对象

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
复制代码

这个方法里就是Retrofit设计的精髓,采用了外观模式和动态代理模式。也是这个方法创建了API接口的实例。这个方法步骤有点多,一步步来看。首先看到的是validateEagerly标志,它在这里被使用,判断为true时会调用eagerlyValidateMethods方法,进入eagerlyValidateMethods方法。

  private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
      }
    }
  }
复制代码

eagerlyValidateMethods方法中循环遍历了由参数传入的网络请求接口类中的所有方法,并且判断方法不是默认方法且不是静态方法就调用loadServiceMethod将该方法传入。loadServiceMethod是一个用来解析API接口中的方法的方法,具体点来说就是上面示例中ApiService中的每个方法会被解析成一个ServiceMethod对象并进行缓存。具体后面再看,还是回到create方法。

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(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);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
复制代码

eagerlyValidateMethods默认为false所以默认会走到return (T) Proxy.newProxyInstance这个方法。这里使用了动态代理,invoke方法中先判断方法是否是Object类中方法,是就不做修改按照原样执行。再调用platform.isDefaultMethod判断是否是默认方法,是就调用platform.invokeDefaultMethod,该方法中抛出异常。最后是最重要的,也是解析正常接口方法走到的是最后这行return loadServiceMethod(method).invoke(args != null ? args : emptyArgs)。正常情况下这里还是会先调用loadServiceMethod方法,现在再来详细看一下这个方法。

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

loadServiceMethod中首先在serviceMethodCache缓存中查找这个方法,如果找得到直接返回。找不到进入同步代码块,这里是DCL单例模式,同步代码块中再次判断缓存中是否存在该方法,不存在调用ServiceMethod.parseAnnotations方法解析方法注解获得解析结果,并将结果ServiceMethod加入缓存。接下来看看ServiceMethodparseAnnotations这个解析注解的方法。

  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    // 解析注解获得一个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.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }
复制代码

ServiceMethodparseAnnotations方法中主要做了三件事。一是调用RequestFactoryparseAnnotations方法解析注解获得一个RequestFactory对象。二是获取方法的返回类型并校验异常情况。三是继续调用HttpServiceMethodparseAnnotations方法。先来看RequestFactoryparseAnnotations方法。

  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }
复制代码

RequestFactoryparseAnnotations方法中以建造者模式创建一个RequestFactory对象。先看Builder构造方法。

  Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      // 初始化获取方法上的注解,对应使用例子中的@GET
      this.methodAnnotations = method.getAnnotations();
      // 初始化获取方法参数类型,对应使用例子中的方法参数key、city的类型String
      this.parameterTypes = method.getGenericParameterTypes();
      // 初始化获取方法参数上的注解,对应使用例子中的方法参数key、city上的@Query
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }
复制代码

构造函数中依旧做的是属性的初始化工作,还是继续看其build方法。

 RequestFactory build() {
	  // 循环解析方法上的注解
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
	  // HTTP请求方法类型为空抛出异常
      if (httpMethod == null) {
        throw methodError(method, "HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }
	  // 注解错误抛出异常,Multipart与FormUrlEncoded必须在有请求体的post请求上使用
      if (!hasBody) {
        if (isMultipart) {
          throw methodError(method,
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError(method, "FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }
	  // 获得方法参数个数
      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);
      }
	  // 判断各种使用错误情况抛出对应异常
      if (relativeUrl == null && !gotUrl) {
        throw methodError(method, "Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError(method, "Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError(method, "Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError(method, "Multipart method must contain at least one @Part.");
      }
	  // 创建RequestFactory对象返回
      return new RequestFactory(this);
    }
复制代码

build方法中做了四件事。一是解析方法上的注解获得HTTP请求方法类型和其他请求头信息。二是解析方法的参数,三是抛出各种错误异常,四是创建RequestFactory实例返回。接着简单看下parseMethodAnnotation方法。

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

该方法中主要是判断方法上注解的各种类型包括GETPOST等各种请求类型又或者是其他自定义请求头retrofit2.http.Headers等,找到对应类型的解析方法进行进一步的解析。于此看来RequestFactory中是将我们在ApiService中写的方法和方法参数进行解析,解析后封装成对象以供后续使用。看完RequestFactory再回到ServiceMethodparseAnnotations方法中。该方法最后又调用了HttpServiceMethodparseAnnotations方法于是继续跟踪查看。

   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) {
      ......
    } else {
	  // 非Kotlin方法走这边,获得方法返回类型
      adapterType = method.getGenericReturnType();
    }
	// 调用createCallAdapter创建一个CallAdapter网络请求适配器
    CallAdapter<ResponseT, ReturnT> callAdapter =
        createCallAdapter(retrofit, method, adapterType, annotations);
	// 获得CallAdapter的响应类型
    Type responseType = callAdapter.responseType();
	// 是okhttp中的Response抛出异常
    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.");
    }
	// 调用createResponseConverter方法创建ResponseConverter数据转换器
    Converter<ResponseBody, ResponseT> responseConverter =
        createResponseConverter(retrofit, method, responseType);
	 // 获得请求工厂
    okhttp3.Call.Factory callFactory = retrofit.callFactory;
    if (!isKotlinSuspendFunction) {// 不是Kotlin方法走这里
	  // 创建CallAdapted传入之前创建的requestFactory、callFactory、responseConverter、callAdapter
      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);
    }
  }
复制代码

先来梳理下HttpServiceMethodparseAnnotations方法的流程,该方法中主要做了这几件事。首先调用createCallAdapter方法创建一个网络请求适配器,然后调用createResponseConverter方法创建了响应数据转换器,接着从传入的retrofit对象中获取到网络请求工厂callFactory,最后通过以上这几个对象创建了一个CallAdapted返回。下面还是来深入看这些方法先是createCallAdapter

 private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
      Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
    try {
      // 调用retrofit.callAdapter方法
      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);
    }
  }
  
 public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
 }
复制代码

createCallAdapter中调用Retrofit类里的callAdapter方法,进而又调用它的了nextCallAdapter方法返回了一个CallAdapter对象。

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");
    // 从网络请求适配器工厂集合中查找传入的适配器的位置
    // 这里注意到nextCallAdapter方法传递的skipPast参数为null,所以这里indexOf返回-1,最终start为0
    int start = callAdapterFactories.indexOf(skipPast) + 1;
    // 循环遍历网络请求适配器工厂集合
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
     // 调用Factory的get方法获得适配器
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      // 不为空就返回adapter
      if (adapter != null) {
        return adapter;
      }
    }
   ......
  }
复制代码

nextCallAdapter方法中遍历从网络请求适配器工厂集合,根据方法的返回类型调用工厂的get获得CallAdapter。还记得创建工厂集合时默认添加了一个DefaultCallAdapterFactory吗?Retrofit默认方法返回类型Call就对应了这个工厂。进入它的get方法查看一下。

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

DefaultCallAdapterFactoryget方法中根据传入的方法返回类型判断,返回类型不是Call类型就直接返回null。类型正确会返回一个CallAdapter

再回到HttpServiceMethodparseAnnotations方法的流程,createCallAdapter方法之后调用createResponseConverter方法,这两个方法的流程类似,这里就大概的看下。

private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
      Retrofit retrofit, Method method, Type responseType) {
    Annotation[] annotations = method.getAnnotations();
    try {
      // 同样是调用Retorfit中的方法responseBodyConverter
      return retrofit.responseBodyConverter(responseType, annotations);
    } catch (RuntimeException e) { // Wide exception range because factories are user code.
      throw methodError(method, e, "Unable to create converter for %s", responseType);
    }
  }
  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    // 进而调用nextResponseBodyConverter方法
    return nextResponseBodyConverter(null, type, annotations);
  }
  // 该方法逻辑和nextCallAdapter类似
 public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      // 调用数据转换器工厂的responseBodyConverter方法
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

   ......
  }
复制代码

createResponseConverter方法的逻辑流程和之前获得网络请求适配器的流程类似。都是会调用Retrofit类中对应方法,之后再调用对应next方法遍历数据转换器集合,从中获得合适的转换器。这里来看下常用的Gson转换器的responseBodyConverter方法。

public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
复制代码

看到最终会返回一个GsonResponseBodyConverter对象。

终于又回到Retrofitcreate方法里了,由之前分析可知loadServiceMethod方法最终会获得一个CallAdapted对象,这里就会接着调用它的invoke方法,而CallAdapted中没有实现invoke方法,invoke方法在其父类HttpServiceMethod中。

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

invoke方法中创建了一个Call,实现是OkHttpCall,注意这个Call还不是OkHttp中的Call类,它还是Retrofit包中的类。

package retrofit2;
......
final class OkHttpCall<T> implements Call<T> {
  private final RequestFactory requestFactory;
  private final Object[] args;
  private final okhttp3.Call.Factory callFactory;
  private final Converter<ResponseBody, T> responseConverter;

  private volatile boolean canceled;
  // 这个rawCall才是OkHttp中的Call
  @GuardedBy("this")
  private @Nullable okhttp3.Call rawCall;
  ......
  }
复制代码

可以看到这个类确实在retrofit2包下,并且这个类中有个rawCall成员变量,它才是OkHttp包中的Call。回到invoke方法创建完OkHttpCall对象后将其传入adapt方法,这个方法调用的是CallAdapted中的。

@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
      return callAdapter.adapt(call);
    }
复制代码

方法中又调用了callAdapteradapt方法,这里的callAdapter就是前面从适配器工厂集合中找到的,默认的就是DefaultCallAdapterFactoryget方法返回的。

    @Override public @Nullable CallAdapter<?, ?> get(
      Type returnType, Annotation[] annotations, Retrofit retrofit) {
      ......
    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);
      }
    };
  }
复制代码

return方法实现了CallAdapter,其中adapt方法返回的是一个ExecutorCallbackCall类型,它实现了RetrofitCall接口,就是最终返回的类型。至此

3.7 调用网络请求接口对象中的方法

由上一步可知获得网络请求接口类实际使用了动态代理,所以获得的对象不是通过网络请求接口创建的对象而是它的代理对象。所以在这一步调用接口中的方法例如使用例子中的getWeather方法时,会被动态代理对象拦截,进入它的invoke方法,invoke方法中的Method参数此时就是调用的方法getWeather,接着就会像上一步所讲的那样调用loadServiceMethod(method).invoke方法,最终返回一个ExecutorCallbackCall对象。接下来就是发同步和异步请求。

3.8 同步请求execute方法

同步请求方法调用的是execute方法,进入实现类ExecutorCallbackCallexecute方法查看。

@Override public Response<T> execute() throws IOException {
      return delegate.execute();
}
复制代码

方法里直接调用了delegate.execute方法,这个delegate由构造方法传入,来看构造方法。

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

构造方法中初始化了两个成员变量,一个callbackExecutor由之前的代码调用可以发现这个就是主线程的回调执行器,第二个delegate就是在invoke方法中创建的OkHttpCall。所以这里再到OkHttpCall里去查看它的execute方法。

  @Override public Response<T> execute() throws IOException {
    okhttp3.Call call;
    synchronized (this) {
	  ......

      call = rawCall;
	  // 当前call为空
      if (call == null) {
        try {
         // 调用createRawCall创建一个call
          call = rawCall = createRawCall();
        } catch (IOException | RuntimeException | Error e) {
          throwIfFatal(e); //  Do not assign a fatal error to creationFailure.
          creationFailure = e;
          throw e;
        }
      }
    }
	// 取消调用call.cancel
    if (canceled) {
      call.cancel();
    }
	// 调用call.execute方法获得OkHttp中Response再调用parseResponse方法解析响应结果返回
    return parseResponse(call.execute());
  }
复制代码

execute方法中首先判断当前call是否为空,为空则调用createRawCall方法创建一个Call,这个对象类型可以看到就是OkHttp中的Call类型,接着调用call.execute方法获得OkHttp返回的Response,最后再调用parseResponse方法解析响应结果返回。这里先看下createRawCall方法。

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

该方法很简单,先调用requestFactory.create方法创建一个OkHttp中的Request,这里就不详细看了,requestFactory创建时大概看过,其中封装了一个请求方法的详细信息。之后调用callFactory.newCall方法获得了返回的Call对象。这里的callFactory通过前面的代码知道默认是一个OkHttpClient。所以这个方法就相当于是执行了OkHttpClient.newCall(request),这就是OkHttp的基础请求操作了。获得到OkHttp返回的Response后继续调用了parseResponse方法解析,将响应结果转换成RetrofitResponse

  Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
	// 获得响应中的body
    ResponseBody rawBody = rawResponse.body();
    // 移除rawResponse中的body只包含状态
    rawResponse = rawResponse.newBuilder()
        .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
        .build();
	// 获得响应中的响应码
    int code = rawResponse.code();
	// 响应码小于200大于300表示错误
    if (code < 200 || code >= 300) {
      try {
        // Buffer the entire body to avoid future I/O.
        ResponseBody bufferedBody = Utils.buffer(rawBody);
	// 调用Response.error将body和rawResponse返回
        return Response.error(bufferedBody, rawResponse);
      } finally {
        rawBody.close();
      }
    }
	// 响应码为204或者205
    if (code == 204 || code == 205) {
      rawBody.close();
	  // 响应码为204或者205调用Response.success返回响应体为空
      return Response.success(null, rawResponse);
    }
	// 将响应体body封装成一个ExceptionCatchingResponseBody对象
    ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
    try {
	   // 调用responseConverter.convert方法转换响应结果
      T body = responseConverter.convert(catchingBody);
	  // 调用Response.success将转换好的body和rawResponse返回
      return Response.success(body, rawResponse);
    } catch (RuntimeException e) {
      // If the underlying source threw an exception, propagate that rather than indicating it was
      // a runtime exception.
      catchingBody.throwIfCaught();
      throw e;
    }
  }
复制代码

parseResponse方法中将响应体和其他响应状态信息分离,响应体单独拿了出来进行解析。该方法里的流程为判断响应码不在200到300之间及异常情况直接调用Response.error(bufferedBody, rawResponse)返回一个Retrofit中的Response,返回码为204或者205表示响应成功但是没有响应体返回,所以调用Response.success传入的响应体为null。除此以外其他正常情况就调用数据转换器responseConverterconvert方法转换响应,转换后的结果通过Response.success(body, rawResponse)返回Retrofit中完整的响应结果。

  public static <T> Response<T> error(ResponseBody body, okhttp3.Response rawResponse) {
    checkNotNull(body, "body == null");
    checkNotNull(rawResponse, "rawResponse == null");
    if (rawResponse.isSuccessful()) {
      throw new IllegalArgumentException("rawResponse should not be successful response");
    }
    return new Response<>(rawResponse, null, body);
  }
  public static <T> Response<T> success(@Nullable T body, okhttp3.Response rawResponse) {
    checkNotNull(rawResponse, "rawResponse == null");
    if (!rawResponse.isSuccessful()) {
      throw new IllegalArgumentException("rawResponse must be successful response");
    }
    return new Response<>(rawResponse, body, null);
  }
复制代码

这里先看errorsuccess方法,这两个方法比较类似,都是先判断是否成功,与预期不符直接抛出异常。判断完后都是创建了一个Retrofit中所需要的相应对象Response返回就行了。同步请求方法的流程到这里就结束了。最后再来关注下数据转换的responseConverter.convert方法,这里调用了数据转换器工厂里的convert方法,因为平常使用Gson解析比较多,所以这里还是看从Gson对应的工厂GsonConverterFactory获得的转换器GsonResponseBodyConverter

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
  private final Gson gson;
  private final TypeAdapter<T> adapter;
  GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
    this.gson = gson;
    this.adapter = adapter;
  }
  @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      T result = adapter.read(jsonReader);
      if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
        throw new JsonIOException("JSON document was not fully consumed.");
      }
      return result;
    } finally {
      value.close();
    }
  }
}
复制代码

GsonResponseBodyConverterconvert方法实现就比较简单了,就是调用Gson中的方法了。通过构造中传入的Gson对象创建一个JsonReader并将响应体的字符流传入,最后调用TypeAdapter.read(jsonReader)将请求体解析得到对应实体类。

3.9 异步请求enqueue方法

异步和同步一样,同样调用了ExecutorCallbackCall的对应enqueue方法,方法中传入了一个异步回调Callback

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

ExecutorCallbackCallenqueue方法同样进而又调用了OkHttpCall中的enqueue方法传入又一个回调的Callback。在这个回调的成功onResponse和失败onFailure方法中都先调用了callbackExecutor.execute进行了线程切换。callbackExecutor就是一开始初始化时创建的MainThreadExecutor,所以这里再次回调的callback.onFailurecallback.onResponse都会执行在主线程中,将响应的结果传递到外层。至此异步调用流程也结束了。最后再进入OkHttpCall中的enqueue方法看一下。

@Override public void enqueue(final Callback<T> callback) {
    checkNotNull(callback, "callback == null");
    okhttp3.Call call;
    Throwable failure;
    synchronized (this) {
	  ......
      call = rawCall;
      ......
      if (call == null && failure == null) {
        try {
        // 创建OkHttp中的Call
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          throwIfFatal(t);
          failure = creationFailure = t;
        }
	......
	// 判断取消
    if (canceled) {
      call.cancel();
    }
    // 调用OkHttp中的call.enqueue
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
       // 成功回调
        Response<T> response;
        try {
         // 返回成功解析Response
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }
        try {
         // 调用callback.onResponse
          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 void callFailure(Throwable e) {
        try {
	    // 调用callback.onFailure
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }
    });
  }
复制代码

OkHttpCall中的enqueue方法的逻辑和同步方法的逻辑类似,同样还是先创建OkHttp中的Call,再调用OkHttpCallenqueue方法,成功获得到OkHttp的返回结果后再同样通过parseResponse方法解析,解析之后回调callback.onResponse,若OkHttp返回失败则回调callback.onFailure

工作流程

4. Retrofit源码中的设计模式

4.1 建造者模式

这个模式不用找无论是OkHttp还是Retrofit中都是随处可见。RetrofitRetrofit这个类就是建造者模式。

建造者模式是将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式中有如下角色:

  • Director:导演类。负责安排已有的模块顺序,通知Builder开始建造。
  • Builder:抽象Builder类。规范产品的组件,一般由子类实现。
  • ConcreteBuilder:具体建造者,实现抽象Builder类定义的方法,返回一个组建好的对象。
  • Product:产品类。

例:

/**
 * 产品类
 */
public class Computer {

    private String mCPU;
    private String mMainBoard;
    private String mRAM;

    public void setmCPU(String mCPU) {
        this.mCPU = mCPU;
    }

    public void setmMainBoard(String mMainBoard) {
        this.mMainBoard = mMainBoard;
    }

    public void setmRAM(String mRAM) {
        this.mRAM = mRAM;
    }
}

/**
 * 抽象builder类
 */
public abstract class Builder {
    public abstract void buildCpu(String cpu);
    public abstract void buildMainboard(String mainboard);
    public abstract void buildRam(String ram);
    public abstract Computer create();
}

/**
 * Builder实现类
 */
public class ComputerBuilder extends Builder {

    private Computer computer = new Computer();

    @Override
    public void buildCpu(String cpu) {
        computer.setmCPU(cpu);
    }

    @Override
    public void buildMainboard(String mainboard) {
        computer.setmMainBoard(mainboard);
    }

    @Override
    public void buildRam(String ram) {
        computer.setmRAM(ram);
    }

    @Override
    public Computer create() {
        return computer;
    }
}

/**
 * 导演类
 */
public class Director {

    Builder builder = null;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public Computer createComputer(String cpu, String mainboard, String ram) {
        this.builder.buildCpu(cpu);
        this.builder.buildMainboard(mainboard);
        this.builder.buildRam(ram);
        return builder.create();
    }
}
复制代码

调用:

  Builder builder = new ComputerBuilder();
  Director director = new Director(builder);
  Computer computer = director.createComputer("i7 7700", "华硕M10H", "三星8G DDR4");
复制代码

使用场景:

  1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  2. 相同的方法不同的执行顺序。产生不同的事件结果时。
  3. 多个零件头可以被装配到一个对象中,但是产生的运行结果又不相同时。
  4. 产品类非常复杂,或者产品类中的调用顺序不同而产生了不同的效能。
  5. 在创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象内部组成构件面临复杂的变化。

优点:

使用建造者模式可以使客户端不必知道产品内部组成的细节。 具体的建造这类之间是相互独立的,容易扩展。 由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响

缺点:

产生多余的Build对象及导演类。

4.2 外观模式

Retrofit这个类也符合外观模式。

外观模式是要求一个子系统的外部与内部的通信必须通过一个统一的对象进行。此模式提供一个高层的接口,使得子系统更容易使用。

外观模式中有如下角色:

  • Facade:外观类,知道哪些子系统负责请求,将客户端的请求代理给适当的子系统对象。
  • Subsystem: 子系统类。可以有一个或者多个子系统。实现子系统的功能,处理外观类指派的任务,注意子系统类不含有外观类的引用。

例:

/**
 * 子系统食材类
 */
public class Food {

    public void buy() {
        Log.e("msg", "购买食材");
    }
}

public class Wash {
    public void wash() {
        Log.e("msg", "清洗食材");
    }
}

public class Cook {

    public void cook() {
        Log.e("msg", "开始做菜");
    }
}

public class Serve {

    public void serve() {
        Log.e("msg", "做完上菜");
    }
}

/**
 * 外观类
 */
public class Chef {
    private Food food;
    private Wash wash;
    private Cook cook;
    private Serve serve;

    public Chef() {
        food = new Food();
        wash = new Wash();
        cook = new Cook();
        serve = new Serve();
    }
    public void work(){
        food.buy();
        wash.wash();
        cook.cook();
        serve.serve();
    }
}

复制代码

调用:

Chef chef = new Chef();
chef.work();
复制代码

使用场景:

1、构建一个有层次结构的子系统时,使用外观模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,则可以让其通过外观接口进行通信。
2、子系统往往会因为不断地重构烟花而变得越来越复杂,大多数的模式使用时也会产生很多小的类,这个外部调用他们的用户带来了使用上的困难。可以通过外观模式提供一个简单的接口,对外隐藏子系统的具体实现并隔离变化。
3、当维护一个遗留的大型系统时,可能这个系统已经非常难以维护和拓展,但是因为它含有重要的功能,所以新的需求必须依赖于它,这时候可以使用外观类,为设计粗糙或者复杂的遗留代码提供一个简单的接口,让新系统和外观类交互,而外观类负责与遗留的代码进行交互。

优点:

减少系统的相互依赖,所有的依赖都是对外观类的依赖,于子系统无关。 对用户隐藏了子系统的具体实现,减少用户对子系统的耦合。 加强了安全性。子系统中的方法如果不在外观类中开通,就无法访问到子系统中的方法。

缺点:

不符合开放封闭原则,如果业务出现变更,则可能需要直接修改外观类。

4.3 单例模式

loadServiceMethod方法中创建ServiceMethod时,就使用了单例模式。

单例模式是用来保证一个类仅有一个实例,并且提供一个访问他的全局访问点。

单例模式中有以下角色:

  • Client:高层客户端。
  • Singleton:单例类。

单例模式有很多种写法这里列举几种:

// 饿汉式
// 类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快,基于类加载机制,避免了多线程同步问题,但是没有达到懒加载的效果,如果始终没有使用过这个实例,就会造成内存浪费。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
    return instance;
}
}

// 懒汉式(线程不安全)
// 在第一次调用时初始化,节约了资源但第一次加载时反应稍慢,且多线程下不能正常工作。
public class Singleton {
private static Singleton instance ;
private Singleton() {
}
public static Singleton getInstance() {
    if (instance==null){
        instance=new Singleton();
    }
    return instance;
}
}
    
// 懒汉式(线程安全)
// 多线程下能正常工作,但是每次代用getInstance方法都要同步,造成不必要的同步,并且大部分时候是用不到同步的,不建议使用。
public class Singleton {
private static Singleton instance ;
private Singleton() {
}
public static synchronized Singleton getInstance() {
    if (instance == null){
        instance = new Singleton();
    }
    return instance;
}
}
    
// 双重检查模式(DCL)
// 这种写法进行了两次判空,第一次为了不必要的同步,第二次是Singleton等于null的情况下才创建实例。并且使用volatile虽然会影响性能但是保证程序的正确性。
// 资源利用率高效率高,第一次加载反应稍慢,在高并发下存在一定缺陷。会发生DCL失效。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
    if (instance == null) {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
            }
    }
    return instance;
}
}
    
// 静态内部类单例模式
// 外部类加载时并不需要立即加载内部类,内部类不被加载则不去初始化sInstance,只有调用getInstance 方法时加载SingletonHolder初始化sInstance,不仅保证线程安全,也保证唯一性。推荐使用。
public class Singleton {
private Singleton() {
}
public static Singleton getInstance() {
   return SingletonHolder.sInstance;
}
private static class SingletonHolder {
    private static final Singleton sInstance = new Singleton();
}
}
  
// 枚举单例
// 枚举的实例创建是线程安全的,并且任何情况下都是单例。
public enum Singleton {
INSTANCE;
public void doSomeThing() {
}
}
复制代码

使用场景:

确保某个类有且只有一个对象的场景,避免产生多个对象消耗过多资源,或者某种类型对象只应该有且只有一个。

优点:

1、由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建销毁时,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显。
2、单例模式只生产一个实例所有减少了系统性能的开销,当一个对象产生需要较多的资源时,则可以通过在应用启动时直接生产一个对象,然后永久驻留内存的方式来解决。
3、单例模式可以避免对资源的多重占用,例如一个写文件操作,由于只有一个实例存在内存中,避免对同一个资源同时写操作。
4、单例模式可以在系统设置全局的访问点,优化和共享资源访问。

缺点:

1、单例模式一般没有接口,扩展很困难,若要扩展除了修改代码基本没有第二种途径可以实现。 2、Android中单例对象如果持有Context,那么很容易发生内存泄漏,因此传递给单例模式的Context,最好是Application Context。

4.4 适配器模式

RetrofitDefaultCallAdapterFactory中的get方法返回一个CallAdapter就是一个适配器模式。

适配器模式是把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式中有以下角色:

  • Target:目标角色,也就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。

  • Adapee:源角色,现在需要适配的接口。

  • Adaper:适配器角色,适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。

例: 类适配器模式:

/**
 * Target:需要的5伏电压
 */
public interface FiveVolt {
    public int getVolt5();
}

/**
 * Adaotee:220电压接口
 */
public class Volt220 {

    public int getVolt220() {
        return 220;
    }
}

/**
 * Adapter:将220伏电压转换成需要的5伏电压
 */
public class VoltAdapter implements FiveVolt {

    private Volt220 volt220;

    public VoltAdapter(Volt220 volt220) {
        this.volt220 = volt220;
    }

    @Override
    public int getVolt5() {
        return 5;
    }
}

复制代码

调用:

VoltAdapter adapter = new VoltAdapter(new Volt220());
adapter.getVolt5();
复制代码

对象适配器模式:

/**
 * Target角色
 */
public interface FiveVolt {
    public int getVolt5();
}

/**
 * Adaotee:220电压接口
 */
public class Volt220 {

    public int getVolt220() {
        return 220;
    }
}
/**
 * 对象适配器模式
 */
public class VoltAdapter implements FiveVolt{

    Volt220 mVolt220;

    public VoltAdapter1(Volt220 adaptee) {
        this.mVolt220 = adaptee;
    }

    public int getVolt220(){
        return mVolt220.getVolt220();
    }

    @Override
    public int getVolt5() {
        return 5;
    }
}
复制代码

调用:

VoltAdapter adapter = new VoltAdapter(new Volt220());
adapter.getVolt5()
复制代码

使用场景:

1、系统需要使用现有的类,但此类的接口不符合系统的需要,即接口不兼容。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。 3、需要一个统一的输出接口,而输入端的类型不可预知。

优点:

更好的复用性:系统需要使用现有的类,而此类的接口不符合系统的需要。那么通过适配器模式就可以让这些功能得到更好的复用。
更好的扩展性:在实现适配器功能的时候,可以调用自己开发的功能,从而自然地扩展系统的功能。

缺点:

过多的使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。

4.5 策略模式

Retrofit中在addCallAdapterFactory时就是一种策略模式。

策略模式是定义一系列的算法,把每一个算法封装起来,并且是他们可互相替换。策略模式使得算法可独立与它的客户而独立变化。

策略模式中有以下角色:

  • Context:上下文角色。用来操作策略的上下文环境,起到承上启下的作用,屏蔽高层模块对策略、算法的直接访问。
  • Stragety:抽象策略角色,策略、算法的抽象,通常为接口。
  • ConcreteStragety:具体策略的实现。

例:


/**
 * 抽象策略接口
 */
public interface Calculate {
    public double calculate(double num1,double num2);
}

/**
 * 具体策略实现类
 */
public class AddCalculate implements Calculate {
    @Override
    public double calculate(double num1, double num2) {
        return num1+num2;
    }
}
/**
 * 具体策略实现类
 */
public class SubtractCalculate  implements Calculate {
    @Override
    public double calculate(double num1, double num2) {
        return num1-num2;
    }
}
/**
 * 具体策略实现类
 */
public class MultiplyCalculate implements Calculate {
    @Override
    public double calculate(double num1, double num2) {
        return num1 * num2;
    }
}

/**
 * 上下文角色
 */
public class Context {
    private Calculate calculate;

    public Context(Calculate calculate) {
        this.calculate = calculate;
    }

    public double calculate(double num1, double num2) {
      return   calculate.calculate(num1, num2);
    }
}
复制代码

调用:

        Context context;
        context = new Context(new AddCalculate());
        double addResult = context.calculate(1, 1);

        context = new Context(new SubtractCalculate());
        double subtractResult = context.calculate(1, 1);

        context = new Context(new MultiplyCalculate());
        double multiplyResult = context.calculate(1, 1);
复制代码

使用场景:

1、对客户隐藏具体策略(算法)的实现细节,彼此完全独立。 2、针对同一类型问题多种处理方式,仅仅是具体行为有差别。
3、在一个类中定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的Stragety类中,以代替这些条件语句。

优点:

使用策略模式可以避免使用多重条件语句。多重条件语句不易维护,而且容易出错。
易于拓展。当要添加策略,只要实现接口就可以了。

缺点:

每个策略都是一个类,复用性小。如果策略过多,类的数量会增多。
上层模块必须知道有哪些策略,才能够使用这些策略,这与迪米特原则相违背。

4.6 装饰模式

Retrofit中的ExecutorCallbackCall使用了装饰模式,其中真正去执行网络请求的还是OkHttpCall

动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。

装饰模式中有以下角色:

  • Component:抽象组件。可以是接口或者抽象类被装饰的最原始对象。
  • ConcreteComponent:组件具体实现类,被装饰的具体对象。
  • Decorator:抽象装饰者。从外来拓展Component类的功能,但对于Component来说无需知道Decorator的存在。在它的属性中必然有一个private变量指向Decorator抽象组件。
  • ConcreteDecorator:装饰者的具体实现类。

例:

/**
 * 抽象组件
 */
public abstract class People {
    public abstract void learn();
}
/**
 * 组件实现类
 */
public class XiaoMing extends People {
    @Override
    public void learn() {
        Log.e("msg","小明学过语文");
    }
}
/**
 * 抽象装饰者
 */
public abstract class Teacher extends People {

    private People people ;

    public Teacher(People people) {
        this.people = people;
    }

    @Override
    public void learn() {
        people.learn();
    }
}
/**
 * 装饰者具体实现类
 */
public class MathTeacher extends Teacher{

    public MathTeacher(People people) {
        super(people);
    }

    public  void  teachMath(){
        Log.e("msg","数学老师教数学");
        Log.e("msg","小明学会了数学");
    }
    @Override
    public void learn() {
        super.learn();
        teachMath();
    }
}
复制代码

调用:

XiaoMing xiaoMing = new XiaoMing();
MathTeacher mathTeacher = new MathTeacher(xiaoMing);
mathTeacher.learn();
复制代码

使用场景:

1、在不影响其他对象的情况下,以动态、透明地方式给单个对象添加职责。
2、需要动态的给一个对象增加功能。这些功能可以动态的撤销。
3、当不能采用继承的方式对系统进行扩充或者采用继承不利于系统若站和维护时。

优点:

通过组合非继承的方式,动态的扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
有效的避免了使用继承的方式扩展一个对象的功能而带来的灵活性差、子类无限制扩张的问题。
具体组件类与具体装饰类可以独立变化。用户可以根据需要增加新的具体组件类和具体装饰类,在使用时进行组合,原有代码无需改变,符合开放封闭原则。

缺点:

因为所有对象都继承自Component,所以如果Component内部发生变化,则不可避免影响所有子类,如果基类改变,势必影响对象的内部。
比继承更加灵活机动的特性,同时也意味着装饰模式比继承更容易出错,排错也很困难,对于多次装饰的对象,需要逐级排查,较为繁琐。所以只有在必要的时候使用装饰模式。
装饰层数不能过多,否则会影响效率。

4.7 简单工厂模式

Retrofit中的Platform类就是简单工厂模式。

简单工厂模式又叫做静态工厂方法模式,这是由一个工厂对象决定创建处哪一种产品类的实例。

简单工厂模式中有以下角色:

  • Factory:工厂类,简单工厂模式的核心,负责创建所有实例的内部逻辑。
  • IProduct:抽象产品类。这是简单工厂模式所创建所有对象的父类,负责描述所有实例共有的公共接口。
  • Product:具体产品类。

例:

/**
 * 手机抽象类
 */
public abstract class MobilePhone {
    /**
     * 查看系统版本
     */
    public abstract void systemVersion();
}
/**
 * 具体产品类
 */
public class IPhoneX extends MobilePhone {
    @Override
    public void systemVersion() {
        Log.d("msg","IOS 11");
    }
}

public class SamsungNote9 extends MobilePhone {
    @Override
    public void systemVersion() {
        Log.d("msg","Android 8.0");

    }
}
/**
 * 手机工厂类
 */
public class MobilePhoneFactory {
    public static MobilePhone createMobilePhone(String name) {
        MobilePhone mobilePhone = null;
        switch (name) {
            case "IPhone":
                mobilePhone = new IPhoneX();
                break;
            case "Samsung":
                mobilePhone = new SamsungNote9();
                break;
            default:
                break;
        }
        return mobilePhone;
    }
}
复制代码

调用:

MobilePhoneFactory.createMobilePhone("IPhone").systemVersion();
复制代码

使用场景:

工厂类负责创建的对象比较少。客户只需知道传入工厂的参数,而无需关心创建对象的逻辑。

优点:

用户根据参数获得对应类的实例,无需关心创建对象的逻辑。降低了耦合性。

缺点:

可实例化的类型在编译期间已被确定,如果需要新类型,则需要修改工厂,这违背了开放封闭原则,简单工厂需要知道所有生成类的类型,档期子类过多或者子类层次过多时不适合使用。

4.8 抽象工厂模式

Retrofit中的Converter就是抽象工厂模式。

定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。

工厂方法模式中有如下角色:

  • Product:抽象产品类。
  • ConcreteProduct: 具体产品类。实现Product接口。
  • Factory:抽象工厂类。返回一个Product对象。
  • ConcreteFactory:具体工厂类。返回ConcreteProduct实例。

例:

/**
 * 产品抽象类
 */
public abstract  class Computer {
    public abstract void systemVersion();
}
/**
 * 具体产品类
 */
public class MacBook extends Computer {
    @Override
    public void systemVersion() {
        Log.d("msg","MAC OS");
    }
}

public class LenovoComputer extends Computer {
    @Override
    public void systemVersion() {
        Log.d("msg","Windows10");
    }
}
/**
 * 抽象工厂类
 */
public abstract class ComputerFactory {
    public abstract <T extends Computer> T createComputer(Class<T> clz);
}
/**
 * 具体工厂
 */
public class ComputerFactoryImpl extends ComputerFactory {
    @Override
    public <T extends Computer> T createComputer(Class<T> clz) {
        Computer computer = null;
        String clzName = clz.getName();
        try {
            //反射生成具体计算机
            computer = (Computer) Class.forName(clzName).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) computer;
    }
}
复制代码

调用:

 ComputerFactory computerFactory = new ComputerFactoryImpl();
        LenovoComputer computer = computerFactory.createComputer(LenovoComputer.class);
        computer.systemVersion();
复制代码

使用场景:

一个对象族有相同的约束,则可以使用抽象工厂模式。

优点:

分离接口与实现,客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已,使其从具体的产品实现中解耦,同时基于接口与实现分离,使抽象该工厂方法模式在切换产品类时更加灵活、容易。

缺点:

一是对类文件的爆炸性增加,二是不太容易扩展新的产品类。

4.9 静态代理模式

Retrofit中的ExecutorCallbackCall类就是个静态代理模式,代理了OkHttpCall

代理模式是为其他对象提供一种代理以控制这个对象的访问。

代理模式中有以下角色:

  • Subject:抽象主题类,声明和真是主题与代理类共同的接口方法。
  • RealSubject:真实主题类。代理类所代表的真实主题。
  • Proxy:代理类。持有对真实主题的引用,在其所实现的接口方法中调用真实主题类中对应的接口方法执行。

例:

/**
 * 抽象接口Subject
 */
public interface Person {
    String sing(String name);

    String dance(String name);
}
/**
 * 委托对象 RealSubject
 */
public class ZhangYiXing implements Person {
    @Override
    public String sing(String name) {
        return "张艺兴唱了一首"+name;
    }

    @Override
    public String dance(String name) {
        return "张艺兴跳了一支"+name;
    }
}

/**
 * Proxy 代理类
 */
public class JingJiRenProxy implements Person {

    private Person zhangYiXing;

    public JingJiRenProxy(Person zhangYiXing) {
        if (zhangYiXing instanceof ZhangYiXing) {
            this.zhangYiXing = zhangYiXing;
        }
    }

    @Override
    public String sing(String name) {
        String money = "我是经纪人,找张艺兴唱歌要出场费100万,先付50万\n";
        String sing = zhangYiXing.sing(name);
        String balance = "\n尾款结清50万";
        return money + sing + balance;
    }

    @Override
    public String dance(String name) {
        String money = "我是经纪人,找张艺兴跳舞要出场费200万,先付100万\n";
        String dance = zhangYiXing.dance(name);
        String balance = "\n尾款结清100万";
        return money + dance + balance;
    }
}
复制代码

调用:

   JingJiRenProxy jingJiRenProxy = new JingJiRenProxy(zhangyixi);
   String sing1 = jingJiRenProxy.sing("梦不落雨林");
   String dance1 = jingJiRenProxy.dance("小天鹅");
复制代码

使用场景:

当无法或者不想直接访问某个对象存在困难时可以通过一个代理对象来简介访问,为了保证客户端的透明性,委托对象与代理对象需要实现相同的接口。

优点:

对代理者与被代理者进行解耦。代理对象在客户端和目标对象之间起到一个中介的作用,这样可以起到对目标对象的保护。

缺点:

对类的增加。

4.10 动态代理模式

RetrofitRetrofit.create方法中就使用了动态代理模式。

动态代理通过反射机制动态的生成代理者的对象,也就是我们在编码阶段压根不需要知道代理谁,代理谁将会在执行阶段决定。

例:

/**
 * Proxy 代理类
 */
public class SuperJingJiRenProxy {

    private Person zhangYiXing;

    public SuperJingJiRenProxy(Person zhangYiXing) {
        if (zhangYiXing instanceof ZhangYiXing) {
            this.zhangYiXing = zhangYiXing;
        }
    }
    public Person getProxy() {
        return (Person) Proxy.newProxyInstance(ZhangYiXing.class.getClassLoader(), zhangYiXing.getClass().getInterfaces(), new InvocationHandler() {

            /**
             * @param proxy     把代理对象自己传递进来
             * @param method    把代理对象当前调用的方法传递进来
             * @param args      把方法参数传递进来
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("sing")) {
                    String money = "我是经纪人,找张艺兴唱歌要出场费100万,先付50万\n";
                    String sing = (String) method.invoke(zhangYiXing, args);
                    String balance = "\n尾款结清50万";
                    return money + sing + balance;
                }
                if (method.getName().equals("dance")) {
                    String money = "我是经纪人,找张艺兴跳舞要出场费200万,先付100万\n";
                    String dance = (String) method.invoke(zhangYiXing, args);
                    String balance = "\n尾款结清100万";

                    return money + dance + balance;
                }
                return null;
            }
        });
    }
}

复制代码

调用:

 SuperJingJiRenProxy superJingJiRenProxy = new SuperJingJiRenProxy(zhangyixi);
 Person proxy = superJingJiRenProxy.getProxy();
 String sing2 = proxy.sing("等你下课");
 String dance2 = proxy.dance("最好舞台");
复制代码

5. 总结

以上就是关于Retrofit的相关总结内容。毕竟现在Retrofit作为主流MVP+Retrofit+RxJava这一套框架的必备成员是非常重要的,也是非常好用的。而且Retrofit中对各种设计模式的组合使用是非常精妙的,深入了解学习还是很有必要的,这对我们自身的编码水平和架构能力都是大有裨益的。

参考资料

Android进阶之光
Android源码设计模式解析与实战

关注下面的标签,发现更多相似文章
评论