老三长谈之Retrofit源码分析
来源:互联网 发布:ubuntu开机grub命令行 编辑:程序博客网 时间:2024/05/02 04:17
#老三长谈之Retrofit源码分析>用了Retrofit大半年了,源码看了好几次。今天我来总结一下吧,以后不看他的源码了。好记性不入烂笔头!!! ##在没有开源框架的日子我们先来看一下没有HTTP框架以前,我们是如何做请求的。 ![](https://i.imgur.com/RgoblZN.png)1.首先build request参数 2.因为不能在主线程请求HTTP,所以你得有个Executer或者线程 3.enqueue后,通过线程去run你的请求 4.得到服务器数据后,callback回调给你的上层。 大概是以上4大步骤,在没有框架的年代,想要做一次请求,是万分痛苦的,你需要自己管理线程切换,需要自己解析读取数据,解析数据成对象,切换回主线程,回调给上层。 这种刀耕火种的原始时代,我们就不要在项目的时候去使用了。效率太低了现在市面上比较火的开源框架是Retrofit,让我们看看,学习一下他的源码. 首先先去下载他的源码吧 https://github.com/square/retrofit/tree/e6a7cd01657670807bed24f6f4ed56eb59c9c9ab Retrofit大概流程图:![](https://i.imgur.com/Sqg6AAW.png) Retrofit的基本使用<Pre>Retrofit retrofit = new Retrofit.Builder() .baseUrl(url) .addConverterFactory(GsonConverterFactory.create()) .build();</pre>所有东西都是先看构造器的 1.通过Retrofit来build一个retrofit对象 使用的是建造者模式 为我们方便的建立一个复杂的对象<pre> public Builder() { this(Platform.get()); }</pre><pre> 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(); }</pre> <Pre>static class Android extends Platform { @Override public Executor defaultCallbackExecutor() { //默认回调到主线程 return new MainThreadExecutor(); } @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) { if (callbackExecutor == null) throw new AssertionError(); //这里默认设置ExecutorCallAdapter return new ExecutorCallAdapterFactory(callbackExecutor); } static class MainThreadExecutor implements Executor { //底层使用handler来进行跳转 private final Handler handler = new Handler(Looper.getMainLooper()); @Override public void execute(Runnable r) { handler.post(r); } } }</pre>上面代码是对retrofit对象的分析对于一个call的建立<pre>IpService ipService = retrofit.create(IpService.class);</pre>使用了门面模式,一个create包含了很多神操作!![](https://i.imgur.com/HsTDwnw.png) 图片看不清晰没所谓,我还会一步一步解析: <pre> Utils.validateServiceInterface(service);//验证是否为接口 if (validateEagerly) { eagerlyValidateMethods(service);//这里有个缓存校验 详情看下面 }</pre> <pre> private void eagerlyValidateMethods(Class<?> service) { Platform platform = Platform.get(); for (Method method : service.getDeclaredMethods()) { if (!platform.isDefaultMethod(method)) {//看一下是否是平台的代码 如果是 就执行下一步 loadServiceMethod(method); } } }</pre>下面方法使用了代理模式,对解耦 但是对性能有点影响<Pre>return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { //获取不同平台,因为支持java Android(不同版本) 对应有不同的API private final Platform platform = Platform.get(); @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)) { //判断这个方法是否是平台里面的默认方法 我们自己写的API不会走这个流程 return platform.invokeDefaultMethod(method, service, proxy, args); } //这里是解析过程 解析注解,传参,把他封装成我们常用的request ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); //使用OKhttp 把我们的serviceMethod做为request去访问网络 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } });</pre><pre> ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method);//在Retrofit内部存在一个serviceMethodCache,主要作用是对各种service的那个指定的方法进行缓存,避免重复加载,比较反射挺耗性能的 if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder<>(this, method).build(); serviceMethodCache.put(method, result);//如果没有就往里面添加 } } return result; }</pre>那么ServiceMethod是如何构建<pre>public ServiceMethod build() { callAdapter = createCallAdapter();//这里你就可以回调器Retrofit建立的时候需要传进来的CallAdapter,尽管也有默认的 responseType = callAdapter.responseType();//CallAdapter的responseType得到的是返回数据的真实类型,然后需要工厂去对他进行转换 if (responseType == Response.class || responseType == okhttp3.Response.class) { throw methodError("'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?"); } responseConverter = createResponseConverter();//GSON或xml之类的向对象所需的东西开始转换 for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } if (httpMethod == null) { throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.)."); } if (!hasBody) { if (isMultipart) { throw methodError( "Multipart can only be specified on HTTP methods with request body (e.g., @POST)."); } if (isFormEncoded) { throw methodError("FormUrlEncoded can only be specified on HTTP methods with " + "request body (e.g., @POST)."); } } int parameterCount = parameterAnnotationsArray.length; parameterHandlers = new ParameterHandler<?>[parameterCount]; for (int p = 0; p < parameterCount; p++) { Type parameterType = parameterTypes[p]; if (Utils.hasUnresolvableType(parameterType)) { throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s", parameterType); } Annotation[] parameterAnnotations = parameterAnnotationsArray[p]; if (parameterAnnotations == null) { throw parameterError(p, "No Retrofit annotation found."); } parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations); } if (relativeUrl == null && !gotUrl) { throw methodError("Missing either @%s URL or @Url parameter.", httpMethod); } if (!isFormEncoded && !isMultipart && !hasBody && gotBody) { throw methodError("Non-body HTTP method cannot contain @Body."); } if (isFormEncoded && !gotField) { throw methodError("Form-encoded method must contain at least one @Field."); } if (isMultipart && !gotPart) { throw methodError("Multipart method must contain at least one @Part."); } return new ServiceMethod<>(this); }</pre>然后我们正则method解析完成在于<pre> //这里是解析过程解析注解,传参,把他封装成我们常用的request ServiceMethod<Object, Object> serviceMethod = ServiceMethod<Object, Object>) loadServiceMethod(method);//详情请看上面的代码</pre>然后需要执行网络访问,我们都知道Retrofit是基于Okhttp的,那么到底是为什么呢?<pre>//使用OKhttp 把我们的serviceMethod做为request去访问网络 OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall);</pre>serviceMethod.callAdapter.adapt(okHttpCall)callAdapter的adapt方法前面讲过,它会创建ExecutorCallbackCall,ExecutorCallbackCall的部分代码如下所示。<Pre> ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) { this.callbackExecutor = callbackExecutor; this.delegate = delegate; } @Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("callback == null"); delegate.enqueue(new Callback<T>() {//可以看出ExecutorCallbackCall是对Call的封装,它主要添加了通过callbackExecutor将请求回调到UI线程。 ExecutorCallbackCall的enqueue方法最终调用的是delegate的enqueue方法 @Override public void onResponse(Call<T> call, final Response<T> response) { callbackExecutor.execute(new Runnable() { @Override public void run() { if (delegate.isCanceled()) { 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); } }); } }); }</pre>这就是Retrofit的大概流程。(其实挺简单)我总结一下吧:首先用Retrofit来build一个retrofit对象 使用的是建造者模式。这个retrofit对象对象,可以定义我们怎么样回调,怎么样去解析我们获得的数据,一些baseurl之类的属性,然后使用门面模式retrofit.create(IpService.class)方便我们使用者去调用方法,动态代理获取serviceMethod.callAdapter.adapt(okHttpCall),然后把返回的结构,可能通过解析后传递给我们用户
阅读全文
0 0
- 老三长谈之Retrofit源码分析
- 老三长谈之Retrofit源码分析
- [Android] Retrofit 源码分析之 Retrofit 对象
- [Android] Retrofit 源码分析之 ServiceMethod 对象
- Retrofit源码分析
- Retrofit源码分析
- Retrofit源码分析
- Retrofit源码简要分析
- Retrofit源码分析1
- Retrofit源码分析
- Retrofit 源码分析
- Retrofit源码分析
- Retrofit源码分析
- Retrofit 2.0源码分析
- Retrofit 源码分析
- Retrofit源码分析
- Retrofit的源码分析
- Retrofit 源码分析
- Ubuntu14.04LTS安装TensorFlow
- str2-json-jq-ajax
- String,StringBuffer,StringBuilder
- vim编辑命令
- memcache理解
- 老三长谈之Retrofit源码分析
- Hello CSDN!
- AES对称式加密及https加密算法中数字证书(非对称加密)
- spring学习笔记六 使用外部属性文件
- LeetCode-13-Roman-to-Integer 无聊模拟,递归
- 邝斌的ACM模板(划分树)
- POJ
- Git 使用
- 大家一起来数二叉树把