在学习了Retrofit分析-漂亮的解耦套路(视频版)后,自己又仔细的钻研了一下Retrofit的源码,也大致清楚了Retrofit进行网络请求的步骤。好记性不如烂笔头,以文章的形式将对于Retrofit的思考记录下来,也加深理解。(如有错误,请不吝赐教)
分析源码的一般姿势
首先我们聊一下对于一个优秀的libary,应该怎样一步一步地分析它。在上面的视频中,介绍了一个很好的方法。分为三个阶段:
- what: 这个框架是用来干什么的,暴露给用户的API都是用来干嘛的。
- how: 这个API内部是怎样实现的,整个框架正常调用时内部是一个怎样的流程。
- why: 为什么要这样实现,有什么好处,可不可以有其他的实现,与原来的实现相比怎么样。
通过了解、深入、思考,将整个框架一层一层地剖析出来,由浅入深,最后从全局再看这个框架,或许我们会不自禁的赞叹代码的美妙。
Retrofit使用(what)
详细的了解Retrofit使用及API可以到Retrofit的Github。
简单使用
首先,我们需要创建一个请求接口,内部是一个请求方法,通过注解的方式定义请求类型及url
public interface IHttpRequestTest {
@GET("api/data/福利/{number}/{page}")
Call<BaseModel<ArrayList<Benefit>>> getBenefits(@Path("number") int number, @Path("page") int page);
}
然后我们就可以愉快地使用Retrofit。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://gank.io/")
.addConverterFactory(GsonConverterFactory.create())
.build();
IHttpRequestTest iHttpRequestTest = retrofit.create(IHttpRequestTest.class);
Call<BaseModel<ArrayList<Benefit>>> call = iHttpRequestTest.getBenefits(40, 2);
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
@Override
public void onResponse(@NonNull Call<BaseModel<ArrayList<Benefit>>> call, @NonNull Response<BaseModel<ArrayList<Benefit>>> response) {
if(response.body() != null && response.body().results != null){
myAdapter.setData(response.body().results);
}
}
@Override
public void onFailure(@NonNull Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
Toast.makeText(MainActivity.this, "请求失败:" + t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
一般http的请求步骤
如上图,对于一般http请求:
- 生成request请求,包括请求类型,url等等,放入Excutor队列
- 请求在Excutor中循环进行httpcall请求
- 等待请求回调
接下来,我们就可以根据这个一般的http请求步骤,通过debug的形式弄清楚Retrofit的内部逻辑。
Retrofit源码解析
探索Retrofit对象初始化时参数的真正含义
首先第一步,就是生产Retrofit对象,并传入基本的参数。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://gank.io/")
.addConverterFactory(GsonConverterFactory.create())
.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();
}
//如果callbackExcutor为空,创建默认的callbackEcxutor
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
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,将使用默认的converterFactories
converterFactories.addAll(platform.defaultConverterFactories());
//返回Retrofit对象,包括在Builder中添加的自定义参数。
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
可以看到,生成的retrofit对象有五个参数必须要存在。
baseUrl
就不用多说了,是必须的。callFactory
使用的是OkHttp3中的OkHttpClient
。callbackExcutor
与callAdapterFactory
中的callAdapter
都对应一般请求步骤中的Excutor
,只不过callbackExcutor
用于在请求内部回调中切换线程,回调的方法存在哪个线程中取决于callbackExcutor
在哪个线程。比如请求要在子线程中,回调的方法在主线程中。callAdapter
是真正的请求对象,callbackExcutor
相当于在callAdapter
中切换线程。converterFactory
是用来解析返回的json数据的。当然这些具体的解释在下面的分析中都会看到。
有源码可看出,默认的callbackExcutor
、callAdapterFactory
、converterFactory
添加都与platform
对象有关。这是一个Platform
类,进入研究一下。
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
@Nullable Executor defaultCallbackExecutor() {return null;}
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {...}
List<? extends Converter.Factory> defaultConverterFactories() {...}
@IgnoreJRERequirement // Only classloaded and used on Java 8.
static class Java8 extends Platform {...}
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
@Override List<? extends Converter.Factory> defaultConverterFactories() {
return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.<Converter.Factory>emptyList();
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
}
内容有点多,这里我只提取了对现在有用的。整体来看,Platform
内部有两个子类继承了该类Android与Java8
。还有一个get方法,获取Platform静态实例,静态实例调用findPlatform()方法。这个方法是根据程序所执行的环境决定是返回一个Android
实例还是Java8
实例或者Platform
实例。这里我们的环境是Android
,所以具体看Android
类中的方法。
- defaultCallbackExecutor()方法,返回了
MainThreadExecutor
类实例。此类在Android类内部,可以清晰的看出其中的handler静态变量是用的主线程的looper。也就是说,默认的callbackExcutor
是运行在主线程的。 - defaultCallAdapterFactories()方法,参数是上面得到的
callbackExcutor
。方法内部创建了ExecutorCallAdapterFactory
类实例,并返回该实例的List。 - defaultConverterFactories()方法,返回了
OptionalConverterFactory
实例,此类中的转换converter()
方法只检查了参数是否为空就将其返回了,说明默认的回调数据是不进行任何转换的。
至此,三个默认参数已确定。
获得自定义接口对象
IHttpRequestTest iHttpRequestTest = retrofit.create(IHttpRequestTest.class);
这是接下来的执行步骤,自定义接口对象由retrofit类中的create方法创建,进去探讨一下。
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 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);
}
});
}
该方法返回的是通过反射获得自定义接口的代理类,并在类中重写了invoke方法。这表明当该类中的方法被执行时,就会拦截此方法。
拦截并解析方法。
Call<BaseModel<ArrayList<Benefit>>> call = iHttpRequestTest.getBenefits(40, 2);
由上一步骤可知,当执行代理类中的方法时,会被拦截。并最终执行loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
方法并返回。先看一下loadServiceMethod(method)
方法。
ServiceMethod<?> loadServiceMethod(Method method) {
//serviceMethodCache,如果执行过此方法,就会有缓存存在这里,直接取出即可
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(this, method)
方法里。
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 T invoke(Object[] args);
}
这是一个抽象类,第一句RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
,是解析方法构建request参数的。RequestFactory类中内容比较多,简单讲一下就是通过获得方法注解、返回类型、方法参数,分别进行解析。
最后它又跑到HttpServiceMethod
类中了。此类继承了ServiceMethod
类。
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method) {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
}
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
return retrofit.responseBodyConverter(responseType, annotations);
}
简化了异常检测类代码,可以看到最后返回的是HttpServiceMethod
类的实例对象,并将retrofit中的一些默认参数传了进去。
解析完了loadServiceMethod(method)
,接下来就是执行invoke方法了。由于loadServiceMethod(method)
返回的是HttpServiceMethod
类的实例对象,所以执行的就是HttpServiceMethod
类中的invoke方法。
@Override ReturnT invoke(Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
此方法很简单,调用了callAdapter中的adapt方法,参数是一个OkHttpCall,字面意思就是将OkHttpCall
适配为其他类。那么这个类是什么什么呢。应该是我们需要返回的Call<BaseModel<ArrayList<Benefit>>>
类。那么怎么适配的呢。上面我们已经说到,retrofi中的默认参数callAdapterFactories
是ExecutorCallAdapterFactory
类,而callAdapterFactories
中的callAdapter
是通过callAdapterFactories.get()
获得的,那么就要去这里面找了。
@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
返回的CallAdapter
对象就是我们需要的。其中重写了adapt方法,也是我们要找的。它又返回了ExecutorCallbackCall
对象,第一个参数就是默认运行在主线程中的callbackExecutor
,第二个参数则是调用时传进来的OkHttpCall
对象。所以说我们需要返回的Call<BaseModel<ArrayList<Benefit>>>
对象就是ExecutorCallbackCall
对象。
依靠OkHttp3进行网络请求,转换回调函数线程到主线程。
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {...});
,终于到最后一步了,拿着上一步返回的Call<BaseModel<ArrayList<Benefit>>>
对象进行异步请求。调用了enqueue方法,也就是ExecutorCallbackCall
中的enqueue方法。
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);
}
});
}
});
}
构造方法给了出来,变量名有些转换。callbackExecutor
依然是在主线程中的那个callbackExecutor
,delegate
是上一步传进来的OkHttpCall
对象。而enqueue的参数callback则是我们自己传入的callback。
方法中首先是delegate
也就是OkHttp3进行的异步请求,在回调的函数中,通过callbackExecutor
使线程切换为主线程,再调用我们自己的callback中对应的函数,使我们可以再回调中进行操作,并且是在主线程中。
OkHttpCall
这个类就不在多讲了,主要作用是retrofit通过OkHttp3进行请求的一个转换。
结语
第一次分析源码,虽然有视频的帮助,但许多类之间跳来跳去的让人眼花缭乱,很艰难地顺了下来。有了这样一个大概的了解,接下来就要分析其设计模式,欣赏其漂亮的解耦套路。当然,如果你已经有了上面的了解,接下来看Retrofit分析-经典设计模式案例就会简单明了。