前言
之前的文章,我们分析了okhttp一个网络请求的一些关键的步骤。今天会再来分析一下基本相当于其孪生兄弟的存在Retrofit。他们都是square公司出品的Android常用开发框架。那么关于Retrofit很多人其实都说是一个网络请求框架,类似于okhttp。那么它真的是这样的吗?我们今天就来看一下:
使用Retrofit进行一次网络请求
既然是开发框架,按照规矩当然是首先会使用啦。关于使用文档,官方提供了github.io页面。既然官方提供了示例,我们按照说明来操作一下,这是获取github某个用户repo的示例。
API定义
retrofit的使用首先要定义一个接口来说明需要请求的接口:
public interface GithubService {
@GET("users/{user}/repos")
Call<List<Object>> listRepos(@Path("user") String user);
}
注意:retrofit中使用了大量的注解,在这个请求定义中可以看到。使用@get表示这个请求为get类型,使用path来与url中已经定义好的参数做映射。
发出请求
private fun makeRetrofitCall() {
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
//相对官方示例,我们多了添加gson解析器这一步。一般如果不添加这里会抛出can not convert exception.
.addConverterFactory(GsonConverterFactory.create())
.build()
val githubService = retrofit.create(GithubService::class.java)
githubService.listRepos("alsowell").enqueue(object : retrofit2.Callback<List<Any>> {
override fun onFailure(call: retrofit2.Call<List<Any>>, t: Throwable) {
}
override fun onResponse(
call: retrofit2.Call<List<Any>>,
response: retrofit2.Response<List<Any>>
) {
Log.d("Retrofit",response.body().toString())
}
})
}
到这里,使用retrofit进行的一个完整的网络请求就完成了。retrofit会使用我们设置的GsonConvertFactory来将response解析成用户希望的格式。使用的时候直接调用response.body()就可以拿到我们想要的数据。下面我一点一点的分析retrofit内部究竟做了什么。
Retrofit.builder()
上面的网络请求中发现,首先要构造出来一个retrofit对象。retrofit跟okhttpclient一样也是使用建造者模式构建出来的,我们来看一下里面有哪些参数:
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;
Platform
platform是retrofit判断当前运行平台的类。目前支持Android、java两个运行平台。在调用Retrofit.builder()方法时就通过调用Platform.get()方法来获取平台类型。同时也会进行一些对应平台的初始化工作。
callFactory
字面意思就是请求工厂类。可以看到其类型是okhttp3定义的call对象。这里其实可以知道retrofit内部请求使用的仍然是okhttp,只不过是对其进行了一次封装,用户可以更方便的进行使用。关于callFactory也是支持用户进行设置进去的。
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.callFactory(OkHttpClient.Builder().build())
.build()
可以看到通过callFactory方法,就可以使用用户自己定义的OkHttpClient对象了。那如果用户没有设置呢?
public Retrofit build() {
//省略代码
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//省略代码
}
会发现,在调用build方法时,retrofit会对当前的callFactory进行空判断。如果当前为null,那么会直接new OkHttpClient()。
HttpUrl
HttpUrl其实也是okHttp包中的类,通过源码可以看到我们设置baseUrl为https://api.github.com/时,内部也是通过HttpUrl.get()方法来进行一些url合法性的校验,以及解析设置后续网络请求会用到的一些参数。具体可在之前OkHttp系列文章中找到。
converterFactories
看见名字我们就知道其实是转换器的工厂。例如我们在前面进行请求时设置了一个GsonConvertFactory来将网络请求的数据解析成我们真正想要的返回。关于Converte和Factory我们将在下文进行详细的分析,这里先保留一些疑问。
callAdapterFactories
翻译过来就是请求适配器工厂,见名知其意即为对请求进行包装来适配不同框架的工厂集。一般我们在使用retrofit时都会结合RxJava来一起使用,那么就是通过callAdapter来进行使用的。同样我们也还是保持一些疑问留给下文详细探究。
callbackExecutor
回调执行器,是不是很好理解?就是我们请求完成之后对我们回调的数据进行线程切换的执行器。同样也可以通过在build过程中用户动态的设置进来。如果没有设置那么retrofit是怎么做的呢?
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
上文我们有说到过platform其实就是运行平台的意思。defaultCallbackExecutor()其实是Platform中定义的方法,每个平台对应其有自己的实现。在Android平台下:
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//静态内部类
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
可以看到默认是在主线程回调返回的,拿到主线程的handler对象,拿到解析完成后的响应数据后通过mainHandler的post方法直接回调到主线程,让用户可以直接在主线程中去更新UI。
validateEagerly
用来配置在使用retrofit.crate()时是否对接口中定义的所有方法进行解析。
上文说到通过Retrofit.builder.xxx.xxx.build()方法最终是拿到一个Retrofit对象的。那我们来接着看一下
Retrofit
首先看一下构造方法:
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.build方法来构建出来我们需要的retrofit对象,那就详细的来看一下build做了哪些操作:
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();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
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);
}
按照调用步骤分析如下:
- 先判断baseUrl是否为null,为null直接抛出异常
- 判断是否有设置callFactory和callBackExecutor,无则使用默认的。具体前文有介绍
- 将平台默认的适配器添加到最后,来看一下Android平台默认的适配器
//这里传入的executor为上文中用户自定义或者android平台的默认MainExecutor //关于DefaultCallAdapterFactory将在后续详细分析 List<? extends CallAdapter.Factory> defaultCallAdapterFactories( @Nullable Executor callbackExecutor) { return singletonList(new DefaultCallAdapterFactory(callbackExecutor)); } - 定义一个大小为1+用户设置转换器集合size+系统默认转换器size的集合
- 将retrofit内置的转换器添加进去
- 将用户设置的转换器添加进去
- 添加平台默认的转换器
- Android平台下仅仅在api>24时候添加进来一个OptionalConverterFactory,其他时候为一个空数组
- 最终通过调用Retrofit的构造方法来成功构建出Retrofit对象
构造无非是把我们在builder中设置的参数传递进来并赋值给类中定义的变量。我们来看一下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;
除了serviceMethodCache,其他变量均已经在我们在build时设置过。
serviceMethodCache
可以看到serviceMethodCache是一个HahshMap集合,实际上是对我们在接口中定义的方法的缓存。是否还记得我们通过注解定义了请求方法类型、请求参数等。我们来看一下ServiceMethod这个类
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);
}
这里是定义的一个带有泛型的抽象类,通过parseAnnotations()来对我们在定义方法时候的注解进行解析。我们具体来看一下parseAnnotations()方法

Retrofit.create()
按照调用流程我们拿到retrofit对象之后会通过retrofit.create(service)方法来拿到一个Service。来看一下具体实现:
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);
}
});
}
简单翻译一下注释:是我们在service接口中定义的方法的具体实现。具体来看代码:
- 通过validateEagerly变量来判断是否提前将接口类中的所有方法解析出来。具体解析分析见下文
- 验证接口类的合法性
- 必须是接口定义
- 接口类中不能有内部接口类
- 返回动态代理的具体实现(关于动态代理,这里提供一篇优秀的文章:10分钟看懂动态代理设计模式)
- 先来看一下Proxy.newProxyInstance这个方法传入的参数。
- ClassLoader:对应我们传入的service的classLoader
- Class<?>[]:需要被代理的接口类,这里传入我们定义的service
- InvocationHandler:使用默认的InvocationHandler
- 具体看一下InvocationHandler方法里面做了什么事情?
- 首先拿到当前运行的平台(这里特指android)
- 定义一个空的对象数组
- 看一下invoke方法里面的调用逻辑
- 如果代理的方法是从一个object中的那么直接走原来的方法
- 根据平台类型来判断执行分支(android version 24以后可能是发生了改动)Android platform这里是做了兼容是不会进来的
- 返回loadServiceMethod.invoke()方法的返回
- 先来看一下Proxy.newProxyInstance这个方法传入的参数。
loadServiceMethod
经过上面的分析知道,retrofit.create()方法返回的是loadServiceMethod.invoke()的代理实现。那来看一下这个是做了什么事情。
- 注:上文说到的提前解析其实也是调用的这个方法,在for循环中进行
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.parseAnnotations()方法将定义的请求解析出来并缓存(关于解析的具体逻辑,上文也说到过看似复杂其实就是按照特定的规则将定义的信息取出,感兴趣的同学可以具体看一下)。这里详细解析一下在解析之外做的事情,见下文。
HttpServiceMethod
在loadServiceMethod方法中调用了ServiceMethod.parseAnnotations()来解析我们在接口方法中定义的一些参数,最终返回的是HttpServiceMethod.parseAnnotations()的返回。
HttpServiceMethod其实继承于ServiceMethod,ServiceMethod定义了一个invoke的抽象方法。还记得在retrofit create中返回的是ServiceMethod.invoke()吗?
还是先看一下在HttpServiceMethod的parseAnnotations中做了什么事情
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) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//创建请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
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.");
}
//创建响应体转换器
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
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);
}
}
这里我们来分析几个主要的函数:
- createCallAdapter
- 创建请求适配器,这里只放一些关键代码。
//createCallAdapter return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); //retrofit.callAdapter return nextCallAdapter(null, returnType, annotations); //nextCallAdapter int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter; } }- 可以看到这里是从我们之前在创建retrofit时候定义的callAdapterFactories中取出一个CallAdapter(DefaultCallAdapterFactory)
- 创建请求适配器,这里只放一些关键代码。
- createResponseConverter
- 创建响应转换器
//createResponseConverter return retrofit.responseBodyConverter(responseType, annotations); //retrofit.responseBodyConverter return nextResponseBodyConverter(null, type, annotations); //nextResponseBodyConverter int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked return (Converter<ResponseBody, T>) converter; } }- 可以看到createResponseConverter与createCallAdapter类似,均是从之前定义的列表中返回。
- 创建响应转换器
|
题外话:曾经遇到一道面试题:retrofit是什么时候将接口中定义的方法解析出来的?是一次性将所有方法解析出来还是使用到的时候在解析? 分析到这里,答案其实很简单了。默认情况下,用户没有通过validateEagerly()方法设置提前解析的话,retrofit是地用到具体方法的时候才会将方法解析出来,这样就可能尽可能的降低内存消耗。如果设置为true的情况,那么就是直接在create创建retrofit对象的时候将接口类中定义的方法一次性全部解析出来。 |
方法调用
我们分析了retrofit的create方法其实动态代理了我们在接口中定义的方法。那接着来看一下在调用方法的时候是干了什么
@GET("users/{user}/repos")
Call<List<Object>> listRepos(@Path("user") String user);
val listRepos = githubService.listRepos("alsowell")
可以看到我们在接口中定义的方法的返回其实是一个call对象,还记得okhttp中的call吗?你是不是以为是一个东西?但是其实这个是retrofit内部自己定义的。
经过前文的分析我们知道当我们调用接口里面的方法时候,其实会调用invoke方法。并且这里实际调用的是HttpServiceMethod的invoke()方法。我们来看一下做了什么操作。
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
这里的okhttpCall其实是retrofit对okhttp的封装,这里是进行了简单的赋值操作。 最终返回的是adapt(call,args)。继续往下看,adapt其实是CallAdapter接口中定义的方法。还记得我们在build retrofit时默认的DefaultCallAdapterFactory吗?具体的实现是由它来做的。
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);
}
};
可以看到最终会返回ExecutorCallbackCall,他也是继承于Call
ExecutorCallbackCall
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@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) {
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);
}
});
}
});
}
@Override public boolean isExecuted() {
return delegate.isExecuted();
}
@Override public Response<T> execute() throws IOException {
return delegate.execute();
}
@Override public void cancel() {
delegate.cancel();
}
@Override public boolean isCanceled() {
return delegate.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // Performing deep clone.
@Override public Call<T> clone() {
return new ExecutorCallbackCall<>(callbackExecutor, delegate.clone());
}
@Override public Request request() {
return delegate.request();
}
}
上文介绍过retrofit的call对象其实是对okhttpcall的封装。基本上与ok的方法相同。通过create动态代理拿到接口的代理类后可以直接调其中定义的方法。那么在执行enqueue方法时的具体实现可以在上文中代码看到,retrofit是定义了
final Call<T> delegate;
这么一个泛型对象来进行真正的执行。其实在上文也分析到了这里的delegate其实是retrofit内部封装的OkHttpCall类,这个也是我们在build retrofit时通过addConverterFactory设置进来或者默认的。
- 所以可以说retrofit执行网络请求的底层依然是okhttp,此结论成立。
执行完毕后会推过设置的callBackExecutor回调出去,默认是主线程。
解析阶段
上文既然说到我们是通过retrofit封装的OkhttpCall对象实际调用的还是okhttp来进行网络请求,之后拿到响应再回调到主线程。但是我们在ExecutorCallbackCall好像并没有看到解析response的过程,那用户是怎么拿到解析之后的返回呢?
既然这里没有,那我们肯定要追根溯源去实际返回响应的地方找一下:
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
}
}
});
可以看到里面有一句关键的代码parseResponse(rawResponse);,继续往下看:
T body = responseConverter.convert(catchingBody);
在这个方法里面找到这个关键的一句,经过我们之前设置的converter转换之后返回的是我们在方法里面定义的泛型。
总结
上面分析了这么多,先来总结一下Retrofit的大概流程
- 定义一个接口类,定义出我们需要请求的方法
- 通过builder模式构建出retrofit对象
- 调用create()方法通过动态代理的方式返回实际的代理对象
- 通过代理对象来调用接口中定义的方法
- enqueue或者excute实际上是调用addCallAdapterFactory中设置的(默认是okhttp)
- 通过okhttp来进行实际的网络请求
- 通过设置的converter来对返回的response进行解析成用户定义的格式
- 通过callBackExecutor回调给调用方(默认是主线程)
至此,我们对Retrofit源码的探究终于可以说是告一段落了,跟OkHttp一样,retrofit的源码同样有很多值得我们学习的地方,例如动态代理的实现。整篇文章下来可能有很多不严谨的地方,这里只是记录个人对于Retrofit的理解,希望大家多多指正。