Retrofit 2.9.0 源码解析
1、前言
在平时开发过程中,我们经常会用到Retrofit
+OkHttp
作为我们的网络请求框架;其简洁易用的特性,为我们的开发工作带来很大的便利性。
那么在使用过程中有没有以下疑问呢?
a. Retrofit
是如何通过Interface Service
声明来实现网络请求的;
b. Retrofit
是如何支持Kotlin
协程的(即如何使用suspend
来实现将Call<Response>
直接转换为Response
的呢);
c. Retrofit
在设计中使用了哪些设计模式呢;
2、Retrofit
是如何通过Interface Service
声明来实现网络请求的
我们先来看一下Retrofit
的初始化和请求示例:
//1. 创建retrofit 实例,这里使用到了建造者模式
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
//2. 通过retrofit 实例,创建Service实例,这里使用到了外观模式,策略模式,
GitHub github = retrofit.create(GitHub.class);
// 3. 通过Service实例获取请求实例Call
Call<List<Contributor>> call = github.contributors("square", "retrofit");
//4. 通过请求实例 Call 发送请求,包含两种方式,异步和同步
//4.1 同步发送
List<Contributor> contributors = call.execute().body();
//4.2 异步发送
call.enqueue(new Callback<List<Contributor>>() {
@Override
public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
//request success
List<Contributor> contributors = response.body();
}
@Override
public void onFailure(Call<List<Contributor>> call, Throwable t) {
//request fail
}
});
2.1 创建retrofit 实例
Retrofit retrofit =
new Retrofit.Builder() //步骤1
.baseUrl(API_URL) //步骤2
.addConverterFactory(GsonConverterFactory.create()) //步骤3
.build(); //步骤4
可以看到retrofit
实例的创建,可以分为4步,接下来我们具体看一下这4步涉及到的逻辑
2.1.1 创建Retrofit.Builder
对象
///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;
//步骤1
//默认无参的构造方法
public Builder() {
this(Platform.get());
//通过this调用了有参的构造方法
//通过Platform.get() 获取了Platform 对象并传入
}
Builder(Platform platform) {
this.platform = platform;
}
... //
}
//步骤2
//Platform 类中,通过静态get()方法,获取平台对象。
///Platform 类
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
//步骤3
private static Platform findPlatform() {
//通过`findPlatform()`方法来根据虚拟机属性,创建平台对象。在Android中的虚拟机名称为`Dalvik`,则会创建Android平台对象,否则创建支持java8的平台对象。
return "Dalvik".equals(System.getProperty("java.vm.name"))
? new Android() //
: new Platform(true);
}
//步骤4
//Android 平台类,继承自Platform,
///Android 类
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override
public Executor defaultCallbackExecutor() {
//重写`defaultCallbackExecutor`方法,返回`MainThreadExecutor`对象,用于在服务器返回数据后,将线程切换到主线程展示结果。
return new MainThreadExecutor();
}
@Nullable
@Override
Object invokeDefaultMethod(
Method method, Class<?> declaringClass, Object object, Object... args) throws Throwable {
if (Build.VERSION.SDK_INT < 26) {
throw new UnsupportedOperationException(
"Calling default methods on API 24 and 25 is not supported");
}
return super.invokeDefaultMethod(method, declaringClass, object, args);
}
//步骤5
//装饰类(装饰模式),内部创建了Android 主线程对应的Handler,执行时通过该Handler来切换到主线程
/// MainThreadExecutor 类
static final class MainThreadExecutor implements Executor {
//创建Handler,并绑定主线程Looper
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
//将Runnable切换到主线程执行
handler.post(r);
}
}
}
}
- 通过默认无参的构造方法,在构造方法中通过
this
调用了有参的构造方法,并通过Platform.get()
方法传入参数 - Platform 类中,通过静态get()方法,获取平台对象。
- 通过
findPlatform()
方法来根据虚拟机属性,创建平台对象。在Android中的虚拟机名称为Dalvik
,则会创建Android平台对象,否则创建支持java8的平台对象。 - Android 平台类,继承自Platform,并重写
defaultCallbackExecutor
方法,返回MainThreadExecutor
对象,用于在服务器返回数据后,将线程切换到主线程展示结果。 MainThreadExecutor
类是一个装饰类(装饰模式),内部创建了Android 主线程对应的Handler,执行时通过该Handler来切换到主线程。
2.1.2 baseUrl(API_URL)
//Retrofit.Builder类
public Builder baseUrl(String baseUrl) {
//baseUrl判空处理
Objects.requireNonNull(baseUrl, "baseUrl == null");
//将baseUrl解析Okhttp请求所需要的HttpUrl对象。
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
//将baseUrl路径根据/进行分割,并判断最后是否以/结尾,不是则抛出异常
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()用于配置Retrofit类的网络请求url地址:将传入的String类型url转化为适合OKhttp的HttpUrl类型的url
2.1.3 addConverterFactory(GsonConverterFactory.create())
///Retrofit.Builder类
/**
* 添加一个数据转换器工厂
*/
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
/**
* 添加Call 适配器工厂
*/
public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
/**
* 添加服务器返回数据后的线程转换回调执行器
*/
public Builder callbackExecutor(Executor executor) {
this.callbackExecutor = Objects.requireNonNull(executor, "executor == null");
return this;
}
/// GsonConverterFactory 类
public final class GsonConverterFactory extends Converter.Factory {
public static GsonConverterFactory create() {
创建一个Gson对象
return create(new Gson());
}
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
创建了一个含有Gson对象实例的GsonConverterFactory
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson