前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Retrofit 解析

Retrofit 解析

作者头像
Yif
发布2019-12-26 14:46:17
1.2K0
发布2019-12-26 14:46:17
举报
文章被收录于专栏:Android 进阶

Retrofit

优点

  1. 可以配置不同HTTP client来实现网络请求,如okhttphttpclient
  2. 请求的方法参数注解都可以定制
  3. 支持同步、异步和RxJava
  4. 超级解耦
  5. 可以配置不同的反序列化工具来解析数据,如jsonxml
  6. 使用非常方便灵活
  7. 框架使用了很多设计模式
  8. Retrofit比较好的把几个框架的功能组合起来,并没有重复自造轮子,而是高效的把轮子进行组合。其利用OkHTTP进行网络请求。并且Retrofit与异步请求框架和类解析框架解耦,使得Retrofit可以适配多种框架,使用者可以轻松的选择适合自己项目的异步请求和解析的框架。
  9. Retrofit的面向接口的设计方式也是其主要优势,用户通过编写接口,框架替用户实现,用户与框架的依赖只限于接口,网络请求的相关参数等也更清晰。

缺点

  1. 不能接触序列化实体和响应数据
  2. 执行的机制太严格
  3. 使用转换器比较低效
  4. 只能支持简单自定义参数类型

使用的设计模式

Builder模式

Retrofit在生成Retrofit对象和ServiceMethod对象时候都用到了Builder模式。通过Builder来生成类的实例对象更加优雅,尤其在如果类有多个可选的构造参数时,参数较多,初始化时我们可以指定其中的一些而其他的参数如果不指定可以为默认。 Builder也有缺点:对多生成Builder对象,增加开销,但总的来说在一些场景下还是利大于弊。

工厂模式

RetrofitConverterAdapter都是由抽象工厂模式来生成的。抽象工厂隔离了具体类的生成,系统与产品的创建/组合/表示的过程相独立:RetrofitConverterFactoryAdapterFactory都是在Retrofit对象生成时候制定的,而ConverterAdapter都是在Retrofit代理各个方法时候生成的。

代理模式

Retrofit使用了动态代理,用户编写接口,告诉Retrofit想要什么样的方法,Retrofit通过动态代理来生成实例对象。用动态代理,完成了从接口到实例对象的过程。与静态代理相比,动态代理一套代码可以同时代理多个原始类/接口。

适配器模式

适配器模式用来将接口A转化成接口B,在Retrofit中用来将Call异步接口转化成其他的异步接口。

总结

Retrofit的设计符合了高内聚,低耦合的原则,有效的将其他框架组织起来,并使其之间解耦,这增强了Retrofit的易用性和灵活性。Retrofit合理运用多种设计模式以及其面向接口的编程方式是其达到高内聚低耦合的关键。没有重新造轮子,而是复用其他轮子,让轮子们高效组合到一起也是Retrofit的意义。

Retorfit 使用

代码语言:javascript
复制
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(url)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .build();
ApiService apiService = retrofit.create(ApiService.class);
retrofit2.Call<Student> call = apiService.getStuInfo();
call.enqueue(new retrofit2.Callback<Student>() {
    @Override
    public void onResponse(retrofit2.Call<Student> call, retrofit2.Response<Student> response) {
    //返回数据回调到主线程中处理,这里切换到了主线程进行操作
    }
 
    @Override
    public void onFailure(retrofit2.Call<Student> call, Throwable t) {
 
    }
});
public interface ApiService {
    @GET("https://www.google.com")
    Call<Student> getStuInfo();
}

源码解析

Builder()方法

代码语言:javascript
复制
public Builder() {
  this(Platform.get());
}
//根据不同运行平台,提供不同的线程池
private static final Platform PLATFORM = findPlatform();
 
static Platform get() {
  return PLATFORM;
}
 
private static Platform findPlatform() {
  try {
//Class.forName('')
//要求JVM查找并加载指定的类
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {
//如果是Android平台,就返回Android对象
      return new Android();
    }
  } catch (ClassNotFoundException ignored) {
  }
  try {
//支持Java平台
    Class.forName("java.util.Optional");
    return new Java8();
  } catch (ClassNotFoundException ignored) {
  }
  return new Platform();
}
//Android平台创建的线程池
static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }
 
  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
// 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
    // 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)
、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
//使用了策略模式
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
 
  static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());
 
    @Override public void execute(Runnable r) {
      handler.post(r);
    }
  }
}

baseUrl方法

代码语言:javascript
复制
public Builder baseUrl(String baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
//将String类型的url装换成okhttp适用的HttpUrl类型
  HttpUrl httpUrl = HttpUrl.parse(baseUrl);
  if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
  }
  return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
//将url分解成几个碎片
  List<String> pathSegments = baseUrl.pathSegments();
//拿到最后一个碎片检测url是不是以“/”结尾
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

baseUrl()用于配置Retrofit类的网络请求url地址,将传入的String类型url转化为适合OKhttpHttpUrl类型的url

GsonConverterFactory

代码语言:javascript
复制
//Converter.Factory抽象工厂模式
//GsonConverterFactory具体工厂
public final class GsonConverterFactory extends Converter.Factory {
 
  public static GsonConverterFactory create() {
    return create(new Gson());
  }
 
  @SuppressWarnings("ConstantConditions") // Guarding public API nullability.
  public static GsonConverterFactory create(Gson gson) {
    if (gson == null) throw new NullPointerException("gson == null");
    return new GsonConverterFactory(gson);
  }
 
  private final Gson gson;
 
  private GsonConverterFactory(Gson gson) {
    this.gson = gson;
  }
 
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//创建一个含有gson的工厂对象
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
 
  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
      Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    return new GsonRequestBodyConverter<>(gson, adapter);
  }
}
public Builder addConverterFactory(Converter.Factory factory) {
//将实例放入到数据转换器工厂类中
//适配器模式
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

build方法

代码语言:javascript
复制
public Retrofit build() {
//baseUrl必须要,否则抛异常
  if (baseUrl == null) {
    throw new IllegalStateException("Base URL required.");
  }
 
  okhttp3.Call.Factory callFactory = this.callFactory;
//如果需要对OkhttpClient进行设置,可以构建OkhttpClient,通过callFactory将构建好的传入,
//如果没有设置,就直接初始化一个OkhttpClient对象
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }
//用来将回调传递到UI线程
  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> adapterFactories = new ArrayList<>(this.adapterFactories);
//用于存储Call进行转化对象
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
 
  // Make a defensive copy of the converters.
//用于存储转化的数据对象,如果是Gson 就设置返回转化好的gson对象
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
//返回配置好的retrofit对象
  return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
      callbackExecutor, validateEagerly);
}
//进行OkhttpClient设置
public Builder client(OkHttpClient client) {
  return callFactory(checkNotNull(client, "client == null"));
}
 
public Builder callFactory(okhttp3.Call.Factory factory) {
  this.callFactory = checkNotNull(factory, "factory == null");
  return this;
}

retrofit.create()的create方法

代码语言:javascript
复制
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();
//第一个参数代理对象,调用方法,方法参数
        @Override public 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);
          }
//单例模式创建ServiceMethod
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
//创建OkhttpCall
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//调用okhttpCall返回rxjava的observer对象或者call对象
          return serviceMethod.callAdapter.adapt(okHttpCall);
        }
      });
}
ServiceMethod<?, ?> loadServiceMethod(Method method) {
  ServiceMethod<?, ?> result = serviceMethodCache.get(method);
  if (result != null) return result;
 
  synchronized (serviceMethodCache) {
//首先从serviceMethodCache查询方法是否有缓存,有的话就直接获取,没有就创建一个然后缓存起来
    result = serviceMethodCache.get(method);
    if (result == null) {
      result = new ServiceMethod.Builder<>(this, method).build();
      serviceMethodCache.put(method, result);
    }
  }
  return result;
}
public ServiceMethod build() {
//根据请求网络接口的方法返回值的注解类型,从retrofit中获取对应的网络请求适配器类型
  callAdapter = createCallAdapter();
//获取对应的数据类型
  responseType = callAdapter.responseType();
  if (responseType == Response.class || responseType == okhttp3.Response.class) {
    throw methodError("'"
        + Utils.getRawType(responseType).getName()
        + "' is not a valid response body type. Did you mean ResponseBody?");
  }
  responseConverter = createResponseConverter();
 
  for (Annotation annotation : methodAnnotations) {
    parseMethodAnnotation(annotation);
  }
 
  if (httpMethod == null) {
    throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
  }
 
  if (!hasBody) {
    if (isMultipart) {
      throw methodError(
          "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
    }
    if (isFormEncoded) {
      throw methodError("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; p < parameterCount; p++) {
    Type parameterType = parameterTypes[p];
    if (Utils.hasUnresolvableType(parameterType)) {
      throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
          parameterType);
    }
 
    Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
    if (parameterAnnotations == null) {
      throw parameterError(p, "No Retrofit annotation found.");
    }
 
    parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
  }
 
  if (relativeUrl == null && !gotUrl) {
    throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
  }
  if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
    throw methodError("Non-body HTTP method cannot contain @Body.");
  }
  if (isFormEncoded && !gotField) {
    throw methodError("Form-encoded method must contain at least one @Field.");
  }
  if (isMultipart && !gotPart) {
    throw methodError("Multipart method must contain at least one @Part.");
  }
 
  return new ServiceMethod<>(this);
}

解析网络请求接口中方法的注解 主要是解析获取Http请求的方法 注解包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded 处理主要是调用方法 `parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值。

代码语言:javascript
复制
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);
    if (!Void.class.equals(responseType)) {
      throw methodError("HEAD method must use Void as response type.");
    }
  } 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("@Headers annotation is empty.");
    }
    headers = parseHeaders(headersToParse);
  } else if (annotation instanceof Multipart) {
    if (isFormEncoded) {
      throw methodError("Only one encoding annotation is allowed.");
    }
    isMultipart = true;
  } else if (annotation instanceof FormUrlEncoded) {
    if (isMultipart) {
      throw methodError("Only one encoding annotation is allowed.");
    }
    isFormEncoded = true;
  }
}
private CallAdapter<T, R> createCallAdapter() {
//获取网络接口里的返回值类型
  Type returnType = method.getGenericReturnType();
  if (Utils.hasUnresolvableType(returnType)) {
    throw methodError(
        "Method return type must not include a type variable or wildcard: %s", returnType);
  }
类型不能是void否则抛异常
  if (returnType == void.class) {
    throw methodError("Service methods cannot return void.");
  }
//获取网络接口注解方法
  Annotation[] annotations = method.getAnnotations();
  try {
    //noinspection unchecked
    return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
  } catch (RuntimeException e) { // Wide exception range because factories are user code.
    throw methodError(e, "Unable to create call adapter for %s", returnType);
  }
}
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
  checkNotNull(returnType, "returnType == null");
  checkNotNull(annotations, "annotations == null");
 
  int start = adapterFactories.indexOf(skipPast) + 1;
//遍历CallAdapter.Factory集合,寻找合适工厂,没有提供factory将抛异常
  for (int i = start, count = adapterFactories.size(); i < count; i++) {
    CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
    if (adapter != null) {
      return adapter;
    }
  }
 
  StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
      .append(returnType)
      .append(".\n");
  if (skipPast != null) {
    builder.append("  Skipped:");
    for (int i = 0; i < start; i++) {
      builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
    }
    builder.append('\n');
  }
  builder.append("  Tried:");
  for (int i = start, count = adapterFactories.size(); i < count; i++) {
    builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
  }
//如果最终没有工厂所提供的所需的CallAdapter抛异常
  throw new IllegalArgumentException(builder.toString());
}

call.equeue()方法

代码语言:javascript
复制
ExecutorCallAdapterFactory 类中
@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "callback == null");
//使用静态代理异步请求
  delegate.enqueue(new Callback<T>() {
    @Override public void onResponse(Call<T> call, final Response<T> response) {
// 线程切换,从而在主线程显示结果
// 最后Okhttp的异步请求结果返回到callbackExecutor
// callbackExecutor.execute()通过Handler异步回调将结果传回到主线程进行处理,进行了线程切换
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          if (delegate.isCanceled()) {
            // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
            callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
          } else {
            callback.onResponse(ExecutorCallbackCall.this, response);
          }
        }
      });
    }
 
    @Override public void onFailure(Call<T> call, final Throwable t) {
      callbackExecutor.execute(new Runnable() {
        @Override public void run() {
          callback.onFailure(ExecutorCallbackCall.this, t);
        }
      });
    }
  });
}
 
static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
//创建一个默认的回调器,在主线程中回调方法
    return new MainThreadExecutor();
  }
 
  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
//调用来ExecutorCallAdapterFactory
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
 
  static class MainThreadExecutor implements Executor {
//在主线程中创建handler
    private final Handler handler = new Handler(Looper.getMainLooper());
 
    @Override public void execute(Runnable r) {
//获取主线程的handler,在UI线程网络请求回调显示数据
      handler.post(r);
    }
  }
}

**切换线程的流程:

  1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
  2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutorexecute()通过handler切换到主线程处理返回结果(如显示在Activity等)**

总结

Retrofit 本质上是一个 RESTfulHTTP 网络请求框架的封装,即通过 大量的设计模式 封装了 OkHttp ,使得简洁易用。具体过程如下:

  1. RetrofitHttp请求 抽象 成 Java接口
  2. 在接口里用 注解 描述和配置 网络请求参数
  3. 动态代理的方式,动态将网络请求接口的注解解析成HTTP请求
  4. 最后执行HTTP请求
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年7月17日 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Retrofit
    • 优点
      • 缺点
        • 使用的设计模式
          • Builder模式
          • 工厂模式
          • 代理模式
          • 适配器模式
          • 总结
      • Retorfit 使用
      • 源码解析
        • Builder()方法
          • baseUrl方法
            • GsonConverterFactory
              • build方法
                • retrofit.create()的create方法
                  • call.equeue()方法
                  • 总结
                  相关产品与服务
                  文件存储
                  文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档