内容简介:在学习了首先我们聊一下对于一个优秀的libary,应该怎样一步一步地分析它。在上面的视频中,介绍了一个很好的方法。分为三个阶段:通过了解、深入、思考,将整个框架一层一层地剖析出来,由浅入深,最后从全局再看这个框架,或许我们会不自禁的赞叹代码的美妙。
在学习了 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与 Java 8 。还有一个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分析-经典 设计模式 案例 就会简单明了。
以上所述就是小编给大家介绍的《Retrofit源码分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 以太坊源码分析(36)ethdb源码分析
- [源码分析] kubelet源码分析(一)之 NewKubeletCommand
- libmodbus源码分析(3)从机(服务端)功能源码分析
- [源码分析] nfs-client-provisioner源码分析
- [源码分析] kubelet源码分析(三)之 Pod的创建
- Spring事务源码分析专题(一)JdbcTemplate使用及源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
CLR via C#
Jeffrey Richter / 周靖 / 清华大学出版社 / 2015-1-1 / CNY 109.00
《CLR via C#(第4版)》针对CLR和.NET Framework 4.5进行深入、全面的探讨,并结合实例介绍了如何利用它们进行设计、开发和调试。全书5部分共29章。第Ⅰ部分介绍CLR基础,第Ⅱ部分解释如何设计类型,第Ⅲ部分介绍基本类型,第Ⅳ部分以核心机制为主题,第Ⅴ部分重点介绍线程处理。 通过本书的阅读,读者可以掌握CLR和.NET Framework的精髓,轻松、高效地创建高性能......一起来看看 《CLR via C#》 这本书的介绍吧!