一、简介
Retrofit是最流行的Android网络请求库之一,由著名的Square公司开发,适用于Android、Java、Kotlin的类型安全的Http网络请求。Retrofit是基于OkHttp的封装的,它将接口的定义与使用分离开来了,并和RxJava集成的很好,所以对于异步请求、同步请求也不需要做额外的工作。
二、使用
2.1 添加依赖
在app的build.gradle中添加如下代码。
//Retrofit2
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//Retrofit2 支持的数据转换器 可根据自身数据选择添加依赖
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' //gson
implementation 'com.squareup.retrofit2:converter-jackson:2.9.0' //jackson
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0' //moshi
implementation 'com.squareup.retrofit2:converter-protobuf:2.9.0' //protobuf
implementation 'com.squareup.retrofit2:converter-wire:2.9.0' //wire
implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0' //simplexml
当然你也可以选择去Retrofit官网下载最新的Jar包导入的项目中或者使用Maven添加。
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.9.0</version>
</dependency>
2.2 基本使用
第一步 新建一个ApiService文件
retrofit使用Java接口来封装您的Http API,因此我们需要创建一个接口文件,我这里直接命名为ApiService。
/**
* 封装Http API
*/
public interface ApiService {
}
第二步 创建返回对象,并在ApiService中添加接口API
public interface ApiService {
@GET("/weather/")
Call<WeatherResult> getWeathers(@Query("city") String city);
}
第三步 创建Retrofit实例,并获取ApiService
通过Builder模式创建Retrofit实例,并通过其create方法获取我们上面新建的ApiService实例。
Retrofit retrofit = new Retrofit.Builder()
//设置BaseUrl
.baseUrl(BASE_URL)
//设置数据解析器
.addConverterFactory(GsonConverterFactory.create())
.build();
ApiService apiService = retrofit.create(ApiService.class);
第四步 调用ApiService中的接口获取Call,并调用其execute()\enqueue()实现同步请求\异步请求。
Call<WeatherResult> call = apiService.getWeathers("杭州");
//同步请求
try {
Response<WeatherResult> response = call.execute();
//处理返回结果
} catch (IOException e) {
e.printStackTrace();
}
//异步请求
call.enqueue(new Callback<WeatherResult>() {
@Override
public void onResponse(Call<WeatherResult> call, Response<WeatherResult> response) {
//处理返回结果
}
@Override
public void onFailure(Call<WeatherResult> call, Throwable t) {
}
});
三、原理分析
熟悉了Retrofit的基本使用还不够,正所谓“知其然,知其所以然”,因此理解它的内部原理也是相当重要的,况且这也是一些面试官喜欢提问的问题。接下来...Let`s start!!!
根据使用步骤首先我们来看看Retrofit这个类。在使用的时候我们是通过Builder模式来创建Retrofit实例的,因此他内部一定存在一个Builder静态内部类,我们着重看下Builder里的各个属性分别表示什么。
public final class Retrofit {
...
public static final class Builder{
// 表示当前使用的平台 当获取到的vm虚拟机名称为Dalvik则为Android平台
private final Platform platform;
// OkHttp3的Call工厂接口,其内部需要实现OkHttp的newCall方法
private @Nullable okhttp3.Call.Factory callFactory;
// 没什么好讲的 HttpUrl是用来封装Url的,使用此类可以组成或分解网络地址
private @Nullable HttpUrl baseUrl;
// 转换器集合 通过转换器来转换返回结果数据
private final List<Converter.Factory> converterFactories = new ArrayList<>();
// CallAdapter集合
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
// callback 回调执行器
private @Nullable Executor callbackExecutor;
// 验证有效性的boolean
private boolean validateEagerly;
...
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();
}
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());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
}
}
通过Builder我们最终创建了Retrofit实例,并将这些参数按需传入了到Retrofit对应的属性中。这里需要注意的是在构建Retrofit实例时,baseUrl是不能为空的,否则会抛出异常。callFactory为空时,默认创建OkHttpClient。callbackExecutor为空时,默认使用platform的defaultCallbackExecutor()获取,在android平台下返回的是MainThreadExecutor(),那么它是个什么东西呢,实际上就是Handler。
static final class Android extends Platform {
Android() {
super(Build.VERSION.SDK_INT >= 24);
}
@Override
public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
...
static final class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
handler.post(r);
}
}
}
接下来就是通过Retrofit的create()方法来获取我们所封装的API service接口实例。首先其调用validateServiceInterface方法验证传入的ApiService的有效性,并通过前面我们所提到的validateEagerly的布尔值来判断是否将ApiService中定义的有效方法存入ServiceMethodCache集合中缓存起来。回到create方法,我们可以看到它其实是通过动态代理来创建ApiService动态代理实例。
当我们调用ApiService中的方法时,比如:Call<WeatherResult> call = apiService.getWeathers("杭州"); InvocationHandler就会拦截并执行其invoke方法,这时其三个参数分别表示为:
proxy 对应 ApiService.class;
method 对应 getWeathers;
args 对应 "杭州";
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> 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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
=========================================================================================================================
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
...
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
在platform为Android情况下,其isDefaultMethod方法返回false,因此最终调用loadServiceMethod(method).invoke(args);这里的loadServiceMethod方法是不是有点儿眼熟,没错前面调用validateServiceInterface方法验证传入的ApiService的有效性时最终调用的就是这个方法。它将参数Method解析成ServiceMethod,并存入serviceMethodCache缓存中。
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;
}
接下来就是Retrofit的处理请求的核心代码了,首先我们来看下ServiceMethod类,它是一个抽象类,其内部有两个方法parseAnnotations和invoke。parseAnnotations最终调用了HttpServiceMethod的parseAnnotations方法;而invoke方法是个抽象方法,它在HttpServiceMethod中被实现。
//HttpServiceMethod 中的invoke方法
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
Retrofit的动态代理通过invoke最终调用loadServiceMethod(method).invoke(args)为我们构造一个OkHttpCall,所以可想而知,每一个请求都会创建一个OkHttpCall,它就是用来完成网络请求的。我们接口中所看到的Call就是OkHttpCall。
final class OkHttpCall<T> implements Call<T> {
...
@Override
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
...
call.enqueue(
new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
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(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
...
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = getRawCall();
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
...
}
}
当我们发送同步请求则会调用OkHttpCall的execute方法,其内部最终也是调用了enqueue方法来实现的。其最终parseResponse来解析返回的响应体。
//parseResponse 中的部分代码
try {
T body = responseConverter.convert(catchingBody);
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;
}
这里的responseConverter即是我们所添加的数据转换器,而每个数据转换器则会在其内部重写convert来实现数据的转换,比如Json数据转换,其GsonResponseBodyConverter中的convert方法如下:
@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();
}
}
四、总结
Retrofit利用Builder来创建Retrofit对象,在Retrofit中则利用动态代理创建ApiService的动态代理类,当调用ApiService中的方法进行网络请求时,InvocationHandler则会拦截并将请求方法封装成HttpServiceMethod,最终调用其invoke方法创建一个OkHttpCell来实现网络请求。值得注意的为了避免重复请求,Retrofit中使用了serviceMethodCache来缓存HttpServiceMethod。