Retrofit框架源码学习
引用和参考:
从架构角度看Retrofit的作用、原理和启示
Retrofit分析-漂亮的解耦套路
本文有以下内容:
1,Retrofit用于解决什么问题
2,Retrofit怎么实现Request的封装
3,Retrofit中有哪些功能扩展,或者说有哪些可供用户自定义的部分
4,Retrofit有哪些值得学习的设计思想
1,Retrofit用于解决什么问题
Retrofit内部使用了自家的OKHttp来实现网络请求,如果简单的使用,OKHttp已经很方便了,但如果需要定义大批量的Request,就要写很多重复代码。并且网络请求通常使用Rxjava处理并发,不同库之间组合使用时也相对麻烦。
Retrofit简化了这些重复性的代码。我们只需要定义一个网络请求接口,加上注解,Retrofit就能帮我们生成Request并交给OKHttp处理,并且能根据我们的需求,返回生成OKHttp的Call对象或Rxjava的Observable对象,将返回内容解析成我们需要的类型。
Retrofit基本使用流程:
//1,创建OkHttpClient
sOkHttpClient = new OkHttpClient.Builder()
...
.addInterceptor(InterceptorUtil.getCacheInterceptor())
.build();
//2,使用Build模式创建Retrofit
sRetrofit = new Retrofit.Builder()
.baseUrl(sBaseUrl) //主页
.client(sOkHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
//3,定义网络请求API
public interface LoginApi {
public static final String HOST = "http://www.wanandroid.com/tools/mockapi/2164/";
//通过注解封装url请求,接在主页后面
@GET("hotchpotch_login")
Observable<BaseResponse<Login>> login();
}
//4,通过Retrofit将网络请求API转换为实际的网络请求,并获取返回值
return sRetrofit.create(LoginApi.HOST,LoginApi.class);
2,Retrofit怎么实现Request的封装
Retrofit封装自定义interface里有注解的方法:
@GET("hotchpotch_login")
Observable<BaseResponse<Login>> login();
注解中可以描述url和请求方式,Retrofit解析注解并封装进ServiceMethod。通过ServiceMethod可以获取Request:
Request request = serviceMethod.toRequest(args);
其中的解析和转换,是在Retrofit.create(XXX.class)方法中通过动态代理完成的。XXX.class代表自定义接口,里面定义了带注解的方法,代表Request需求。
关于动态代理
我们把定义好的网络访问接口传给Retrofit,就能得到一个可以调用的实现类,这就使用了JDK中Proxy和InvocationHandler组合的动态代理。
proxy的方法:
Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2)
会返回代理类,每当通过代理调用var1(目标类)中方法时,都会变为调用var2中的
Object invoke(Object var1, Method var2, Object[] var3)
invoke函数实现的返回值需要和自定义接口中方法的返回值一致。invoke函数中会帮我们自动实现接口中方法的功能,生成代理类:
@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 {
// 如果是Object中的方法,就正常调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//根据系统平台,生成接口的实现代码
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//将自定义接口的方法转为ServiceMethod,返回自定义接口的代理类
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
3,Retrofit中有哪些功能扩展,或者说有哪些可供用户自定义的部分
这个问题,其实涉及到Retrofit框架的开发原因。
对于一个网络请求,有哪些变量?
url、请求方式(get/post等)、Http请求的Header设置与安全设置等,以及返回的数据类型。
针对易变的url和请求方式,Retrofit使用了方法注解的方式,可读性良好,扩展性优异,但这需要实现对接口函数中注解的解析,这样就有了ServiceMethod。
针对Http请求的各种设置,其实Retrofit没做什么,因为Retrofit使用的OkHttp有拦截器机制,可以应付这种变化。
针对返回的数据类型,默认情况下,Retrofit会把HTTP响应体反序列化到OkHttp的ResponseBody中,加入Converter可以将返回的数据直接格式化成你需要的样子。由于目标数据类型与业务有关,是不确定的,Retrofit无法提供一个万能的转换类,所以Retrofit提供了扩展接口,允许开发者自己定义ConverterFactory和Converter,去实现潜在的数据类型转换。
针对返回的网络工作对象,对于OKHttp来说,一个请求返回的是okhttp3.call这个Call接口,但如果我们要返回Rxjava的ObServable或Flowable接口的网络工作对象,可以使用addCallAdapterFactory添加CallAdapterFactory。
GsonConverterFactory和RxJava2CallAdapterFactory都是Retrofit帮我们写好的,如果有需要,我们可以自己扩展。添加扩展的示例代码如下:
sRetrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(sOkHttpClient)
.addConverterFactory(GsonConverterFactory.create()) //可以把Http访问得到的json字符串转换为Java数据对象BizEntity
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //Rxjava网络工作对象
.build();
return sRetrofit.create(tClass);
下面定义的请求,返回的是Observable网络工作对象,返回值为Gson转成的BaseResponse类。
public interface LoginApi {
public static final String HOST = "http://www.wanandroid.com/tools/mockapi/2164/";
//自定义接口与返回数据模拟返回统一格式数据封装(http://www.wanandroid.com/tools/mockapi)
@GET("hotchpotch_login")
Observable<BaseResponse<Login>> login();
}
4,Retrofit有哪些值得学习的设计思想
stay4it大神的流程图在设计模式的使用上,首先通过外观模式,用Retrofit类封装了各个功能模块的接口,在使用方便的同时,将用户代码和实际的功能模块解耦。
然后,通过动态代理模式,将用户通过注解定义的接口中的方法生成网络请求。
再往后,就是通过适配器模式,将OKHttp的返回适配成用户需要的类型。
另外,就是框架对于面向对象原则的坚持。哪怕是使用自家的OkHttp,哪怕底层使用了OkHttpClient去处理网络请求,但她并没有使用okhttp3.call这个Call接口,而是自己又建了一个retrofit2.Call接口,OkHttpCall继承的是retrofit2.Call,与okhttp3.call只是引用关系。这样的设计符合依赖倒置原则,可以尽可能的与OkHttpClient解耦。
其实,对于设计的体会,是随着自己的经验不断增加的,过一段时间再来看源码,可能又是一堆新的体验。