Retrofit

Retrofit 是一个 RESTful 的 HTTP 网络框架封装,底层使用的 OkHttp.

基本使用

引入依赖
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
创建一个接口作为网络的请求集合,在方法上用注解进行配置
public interface GitHubService {@GET("users/{user}/repos")Call<List<Repo>> listRepos(@Path("user") String user);
}
使用 Retrofit 创建出接口的实例
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()).build();GitHubService service = retrofit.create(GitHubService.class);
调用接口的对应方法,就创建网络请求对象 Call
Call<List<Repo>> repos = service.listRepos("octocat");
使用 Call.enqueue() 或 Call.execute() 发起网络请求
repos.enqueue(new Callback<List<Repo>>() {@Overridepublic void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {Log.e("TAG", "onResponse:" + response.body().get(0).getName());}@Overridepublic void onFailure(Call<List<Repo>> call, Throwable t) {}
});

源码分析

Retrofit 实例创建

Retrofit 实例是通过建造者模式创建的

// Retrofit类
public final class Retrofit {// 网络请求配置对象(对接口中的方法注解解析后得到的对象)// 缓存,存储网络请求中的相关配置,请求的方法,数据转换器,适配器,基地址private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();final okhttp3.Call.Factory callFactory;// 网络请求器的工厂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;}...// Builder类public static final class Builder {private final Platform platform;private @Nullable okhttp3.Call.Factory callFactory;private @Nullable HttpUrl baseUrl;private final List<Converter.Factory> converterFactories = new ArrayList<>();private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();private @Nullable Executor callbackExecutor;private boolean validateEagerly;Builder(Platform platform) {this.platform = platform;// 平台类型对象}public Builder() {this(Platform.get());}// 添加url地址public Builder baseUrl(URL baseUrl) {Objects.requireNonNull(baseUrl, "baseUrl == null");return baseUrl(HttpUrl.get(baseUrl.toString()));}// 添加数据转化器,可以把返回的数据解析成指定的类型public Builder addConverterFactory(Converter.Factory factory) {converterFactories.add(Objects.requireNonNull(factory, "factory == null"));return this;}// 添加网络请求适配器,CallAdatper对原始Call进行再次封装,如Call<R>到Observable<R>public Builder addCallAdapterFactory(CallAdapter.Factory factory) {callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));return this;}...public Retrofit build() {...okhttp3.Call.Factory callFactory = this.callFactory;// 网络请求执行器if (callFactory == null) {callFactory = new OkHttpClient();}Executor callbackExecutor = this.callbackExecutor;if (callbackExecutor == null) {// 如果没指定,则默认使用Platform检测环境时的默认callbackExecutor// 即Android默认的callbackExecutorcallbackExecutor = platform.defaultCallbackExecutor();}// 配置网络请求适配器工厂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());// 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);}}
}

平台类型 Platform

// Platform 类型
class Platform {private static final Platform PLATFORM = findPlatform();static Platform get() {return PLATFORM;}private static Platform findPlatform() {return "Dalvik".equals(System.getProperty("java.vm.name"))? new Android() //: new Platform(true);}...// 用于接收服务器返回数据后进行线程切换在主线程显示结果static final class Android extends Platform {Android() {super(Build.VERSION.SDK_INT >= 24);}@Overridepublic Executor defaultCallbackExecutor() {return new MainThreadExecutor();}// 回调方法执行器static final class MainThreadExecutor implements Executor {private final Handler handler = new Handler(Looper.getMainLooper());@Overridepublic void execute(Runnable r) {handler.post(r);}}}
}

数据转换器工厂 GsonConverterFactory

// GsonConverterFactory.crate() 创建了一个含有 Gson 对象实例
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);}...}

Retrofit 使用建造者模式通过 Builder 类创建了一个 Retrofit 对象,配置了:

  • 平台类型对象 (Platform)
  • url地址(baseUrl)
  • 网络请求工厂(callFactory)
  • 网络请求适配器的集合(adpterFactories)
  • 数据转换器工厂集合(converterFactories)
  • 回调方法执行器(callbackExector)
请求接口实例创建

Retrofit 是通过 外观模式 和 代理模式 使用 Retrofit.create() 方法创建的网络请求接口的实例,从而使得接口 中配置的方法变得可用,这是 Retrofit 代码接口的核心。

外观模式:定义一个统一的接口,外部通过该接口对子系统里的其他接口进行访问

代理模式:通过访问代理对象的方式间接访问目标对象

Retrofit.create() 方法内部,使用的是 Proxy.newProxyInstance() 方法来创建 接口 的实例。这个方法内部会为入参的多个 inteface 创建了一个对象,这个对象实现了所有 interface 的每个方法,并且每个方法的实现都是雷同的:调用对象实例内部的一个 InvocationHandler 成员变量的 invoke() 方法,并把对应的方法信息传递进去。

因此 InvocationHandler 中的 invoke() 方法中的逻辑,就是执行接口中的方法。

// Retrofit类
public <T> T create(final Class<T> service) {validateServiceInterface(service);// 验证接口return (T)// 创建了网络请求接口的动态代理对象Proxy.newProxyInstance(service.getClassLoader(),// 类加载器new Class<?>[] {service},// 要创建哪些接口new InvocationHandler() {// 当接口的方法触发,会间接调用到 InvocationHandler 的 invoke 方法private final Platform platform = Platform.get();private final Object[] emptyArgs = new Object[0];@Overridepublic @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);// 如果是Object类,直接触发方法}args = args != null ? args : emptyArgs;return platform.isDefaultMethod(method)? platform.invokeDefaultMethod(method, service, proxy, args)// 平台默认方法,直接触发方法: loadServiceMethod(method).invoke(args);// 核心是这行代码,加载接口的方法,并执行}});
}
ServiceMethod 的创建

loadServiceMethod(method),这行代码负责读取接口中原方法的信息(包括返回值类型、方法注解、参数类型、参数注解),并把这些信息做初步分析,最后实际返回的是一个 CallAdapted .

// 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类
// ServiceMethod.parseAnnotations
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);
}// HttpServiceMethod类
// HttpServiceMethod.parseAnnotations
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {...CallAdapter<ResponseT, ReturnT> callAdapter =createCallAdapter(retrofit, method, adapterType, annotations);...if (!isKotlinSuspendFunction) {return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);// 关键是这句} else if (continuationWantsResponse) {//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.return (HttpServiceMethod<ResponseT, ReturnT>)new SuspendForResponse<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);} else {//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.return (HttpServiceMethod<ResponseT, ReturnT>)new SuspendForBody<>(requestFactory,callFactory,responseConverter,(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,continuationBodyNullable);}}
OkHttpCall 的创建

invoke(args) 方法的调用,会触发 OkHttpCall 的创建。

// HttpServiceMethod类
@Override
final @Nullable ReturnT invoke(Object[] args) {Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);return adapt(call, args);// 会调用到 CallApter 的 adapter 方法
}

OkHttpCall 是 retrofit2.Call 的子类,OkHttpCall 的创建将 ServiceMethod 解读到信息(RequestFactory、OkHttpClient 和 ResponseConverter)封装进 OkHttpCall,OkHttpCall 在 enqueue() 方法被调用的时候,利用 RequestFactory 和 OkHttpClient 来创建一个 okhttp3.Call 对象,并调用 okhttp3.Call 来进行网络请求的发起,然后利用 ResponseConverter 对结果进行预处理之后,交回给 Retrofit 的 Callback .

适配器的处理

adapt(call, args) 方法调用会触发到 callAdapter.adapt(call) 的调用

callAdapter.adapt(call);

这个⽅法会使⽤⼀个 CallAdapter 对象来把 OkHttpCall 对象进⾏转换,⽣成⼀个新的对象。默认情况下,返回的是⼀个 ExecutorCallbackCall,它的作⽤是把操作切回主线程后再交给 Callback .

如果有自定义的 CallAdapter,这里也可以生成别的类型的对象,例如 RxJava 的 Observable,来让 Retrofit 和 RxJava 结合使用。

Retrofit源码分析相关推荐

  1. Retrofit源码分析一 概览

    Retrofit源码分析一 概览 Retrofit的本质和与Okhttp的关系 ​ 说到Retrofit,免不了要提起Okhttp,因为二者通常是绑定到一起使用的.那么我们首先要明确一点Retrofi ...

  2. Retrofit源码分析笔记(一)

    如遇图片无法加载请点击此链接 我们先从最简单的Retrofit使用方法看 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n7bbuois-1665971394319)( ...

  3. Retrofit源码分析实践(六)【Retrofit 多BaseUrl问题解决】

    Retrofit源码分析&实践系列文章目录 Retrofit源码分析&实践(一)[从使用入手分析源码] Retrofit源码分析&实践(二)[Retrofit 免费的api测试 ...

  4. retrofit 源码分析

    callAdater可以设置RxJava2CallAdapter,目前只可用这个adapter,支持rxjava2的操作:convertAdater可以使用多种进行操作. 调用例子: Retrofit ...

  5. Retrofit跟OkHttp源码分析

    网上已经有了相等多的分析博客,但终归是别人的知识点,倒不如自己走一遍流程,如果你看到了这篇博客,最好自己跟着思路对照源码过一遍哦! Retrofit源码分析 Retrofit的构建 在我们开发工作中使 ...

  6. Retrofit2.0 源码分析

    前言 注解式的框架非常火,注解以其轻量,简洁等特性被人们所喜爱者,关键是它解藕.网络请求的框架非常多,比较受欢迎的当属retrofit和okHttp了.连retrofit都是基于okHttp之上开发的 ...

  7. Android Retrofit 2.0(三)从源码分析原理

    Retrofit·特点 性能最好,处理最快 使用REST API时非常方便: 传输层默认就使用OkHttp: 支持NIO: 拥有出色的API文档和社区支持 速度上比volley更快: 如果你的应用程序 ...

  8. 【Android】Retrofit基础源码分析

    文章目录 流程图 基本使用 1. 创建服务端ApiInterface 2.配置BaseUrl生成Retrofit对象 3.生成服务端ApiInterface对象 4.调用服务端ApiInterface ...

  9. Android框架源码分析——从设计模式角度看 Retrofit 核心源码

    Android框架源码分析--从设计模式角度看 Retrofit 核心源码 Retrofit中用到了许多常见的设计模式:代理模式.外观模式.构建者模式等.我们将从这三种设计模式入手,分析 Retrof ...

  10. Retrofit2源码分析(一)

    本文将顺着构建请求对象→构建请求接口→发起同步/异步请求的流程,分析retrofit2是如何实现的. 组成部分 Retrofit2源码主要分为以下几个部分: retrofit retrofit-ada ...

最新文章

  1. 软件项目管理0709:一个项目经理对产品方案的迷思
  2. Java常用系统变量收集
  3. python才能做爬虫,No,C#也可以!
  4. Linux 内核完成接口
  5. pytorch torchvision.transforms.CenterCrop
  6. [哀悼]5.12地震后把网站改成灰色的方法
  7. citypersons数据集下载
  8. android 动态改变listview的内容
  9. ARM开发6.3.1 基础实训( 1 ) 单个数码 LED 的显示输出系统设计( 1)--LPC21XX
  10. 微信怎么自动加好友java_Xposed-微信自动加好友功能实现
  11. phpcms v9 wap手机门户分页(显示首页末页)
  12. linux运行海康,海康摄像头SDK在Linux、windows下的兼容问题(二)已解决
  13. 常按摩七个地方永葆年轻
  14. 潇洒郎:批量压缩大师——python实现文件批量命名+批量加密码——GUI软件——打包exe文件
  15. iOS12 Xcode10正式版问题汇总以及新特性(持续更新中....)
  16. 惯性传感器实现全身姿态检测
  17. Lq93:复原 IP 地址
  18. 每次启动虚拟机都要重装虚拟机的操作系统
  19. windows7 安装.Net Framework 4.6.2微软官方版(离线安装包)
  20. JAVA 爬虫框架webmagic 初步使用Demo

热门文章

  1. Java二进制zip,excel文件流到前端时,修改jQuery接受二进制数据。转文件后提示文件损坏(不可预料的压缩文件末端)处理
  2. 怎么为PE添加输入法
  3. nginx的安装升级、常用配置(二)
  4. EfficientNet 简介
  5. C# .net+DevExpress自定义控件(UserControl)之分页控件
  6. 友情链接加nofollow_如何在WordPress中Nofollow所有外部链接
  7. mysql怎么打开db文件_mysql的db文件怎么打开?
  8. 小胜智能机器人如何和手机联网_当下热门的人工智能电话机器人会革手机的命吗?...
  9. 访问者模式---萝卜青菜各有所爱
  10. Unity技术手册-编辑器基础入门万字大总结