Android Retrofit源码分析(一边用一边侃)
Posted 冒泡的章鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Retrofit源码分析(一边用一边侃)相关的知识,希望对你有一定的参考价值。
这几天空余时间总是想着写点什么,所以紧跟着之前android盒子模型FlexBoxLayout之后有写下了这篇Retrofit源码分析使用篇。
前言:
Retrofit由于简单与出色的性能,使其安卓上最流行的HTTP Client库之一。
Android Studio开发相关配置如下:
compile "com.squareup.retrofit2:retrofit:2.0.2"
compile "com.squareup.retrofit2:converter-gson:2.0.2"
这里仅仅是简单的说明下使用,不会过多的讲解说明作用,原因就是类似使用文章百度可谓是一堆堆(杂乱无章)
OkHttpClient client = new OkHttpClient(); client.networkInterceptors().add(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Response response = chain.proceed(chain.request()); /*添加需要过滤的请求*/ return response; } });
上述代码代码只有在有需要过滤特殊的网络请求时才有必要,否则可以不用理睬,往下看。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://api.nuuneoi.com/base/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .build();
这里涉及Retrofit的创造和参数的构建,这里回答下上边说道的为什么在不需要进行相应的参数过滤的时候,可以不用指定对应的Client,让我看下源码内部实现:
1 /** 2 * Create the {@link Retrofit} instance using the configured values. 3 * <p> 4 * Note: If neither {@link #client} nor {@link #callFactory} is called a default {@link 5 * OkHttpClient} will be created and used. 6 */ 7 public Retrofit build() { 8 if (baseUrl == null) { 9 throw new IllegalStateException("Base URL required."); 10 } 11 12 okhttp3.Call.Factory callFactory = this.callFactory; 13 if (callFactory == null) { 14 callFactory = new OkHttpClient(); 15 } 16 17 Executor callbackExecutor = this.callbackExecutor; 18 if (callbackExecutor == null) { 19 callbackExecutor = platform.defaultCallbackExecutor(); 20 } 21 22 // Make a defensive copy of the adapters and add the default Call adapter. 23 List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); 24 adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); 25 26 // Make a defensive copy of the converters. 27 List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); 28 29 return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, 30 callbackExecutor, validateEagerly); 31 }
这里是Retrofit内部builder构建类进行build时候执行的方法,这里稍稍关注下行12-15,判断是否callFactory是否为空,那么callFactory对象来自哪里哪?咱们继续深入源码。
/** * Specify a custom call factory for creating {@link Call} instances. * <p> * Note: Calling {@link #client} automatically sets this value. */ public Builder callFactory(okhttp3.Call.Factory factory) { this.callFactory = checkNotNull(factory, "factory == null"); return this; }
这里是给callFactory对象赋值的地方,那我在看谁调用了这个方法。
/** * The HTTP client used for requests. * <p> * This is a convenience method for calling {@link #callFactory}. * <p> * Note: This method <b>does not</b> make a defensive copy of {@code client}. Changes to its * settings will affect subsequent requests. Pass in a {@linkplain OkHttpClient#clone() cloned} * instance to prevent this if desired. */ public Builder client(OkHttpClient client) { return callFactory(checkNotNull(client, "client == null")); }
很显然这里就是我们在初始化Retrofit的时候添加OkHttpClient的地方。这也就是刚才说的为什么但咱们不需要过滤网络请求可以不添加OkHttpClient
这里需要大家稍微记下是ConverterFactory,他的作用是对返回的数据格式化。
这里之所以说道这块以防你需要调整json里面的一些格式,比如,Date Format。你可以创建一个Gson 对象并把它传递给GsonConverterFactory.create(),遇到类似问题可以参考如下处理方式
son gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd‘T‘HH:mm:ssZ") .create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("") .addConverterFactory(GsonConverterFactory.create(gson)) .build();
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
紧接着让我们跟着上边的简单使用来全面走进源码,一窥内部实现方式。
1、这里需要优先记忆的几个对象声明如下:
callFactory:这个参数代表是实现了Call.Factory接口的类的实例,其实也就是OkHttpClient
converterFactories:返回数据格式化类,也就是GonsConverterFactory类
adapterFactories:这个集合对象内部是CallAdapter.Factory接口实现类的实例对象
根据上述的简单使用我们了解到,Retrofit在创建的时候需要传入一个字节码文件,这里姑且不说这个字节码文件是类还是接口,咱们看下源码内部设计。
1 @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety. 2 public <T> T create(final Class<T> service) { 3 Utils.validateServiceInterface(service); 4 if (validateEagerly) { 5 eagerlyValidateMethods(service); 6 } 7 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, 8 new InvocationHandler() { 9 private final Platform platform = Platform.get(); 10 11 @Override public Object invoke(Object proxy, Method method, Object... args) 12 throws Throwable { 13 // If the method is a method from Object then defer to normal invocation. 14 if (method.getDeclaringClass() == Object.class) { 15 return method.invoke(this, args); 16 } 17 if (platform.isDefaultMethod(method)) { 18 return platform.invokeDefaultMethod(method, service, proxy, args); 19 } 20 ServiceMethod serviceMethod = loadServiceMethod(method); 21 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); 22 return serviceMethod.callAdapter.adapt(okHttpCall); 23 } 24 }); 25 }
大家注意下方法内部第3行,Utils.validateServiceInterface(service),这里直接翻译就是是否是有效的服务接口,看名字可能有些人会一下不是很明白,让我看下改方法实现。
1 static <T> void validateServiceInterface(Class<T> service) { 2 if (!service.isInterface()) { 3 throw new IllegalArgumentException("API declarations must be interfaces."); 4 } 5 // Prevent API interfaces from extending other interfaces. This not only avoids a bug in 6 // Android (http://b.android.com/58753) but it forces composition of API declarations which is 7 // the recommended pattern. 8 if (service.getInterfaces().length > 0) { 9 throw new IllegalArgumentException("API interfaces must not extend other interfaces."); 10 } 11 }
直译代码行2,意思是传入的字节码文件是是否是接口,如果不是则抛出一个非法参数异常,这是其一。行8看到该接口是否继承自其它接口,也就是说该接口不允许采用继承的方式。到这里咱们总结了两点
Retrofit的Create方法传入的字节码文件要求如下:
必须是一个接口
该接口不能继承其他接口
2、这里还是create方法的使用,那么接下来我们来看看他们是如何使用接口,完成一系列的网络请求的。
这里首先我们在回到刚才的Create方法中,看下Create方法对应的返回值
1 ...... 2 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, 3 new InvocationHandler() { 4 private final Platform platform = Platform.get(); 5 6 @Override public Object invoke(Object proxy, Method method, Object... args) 7 throws Throwable { 8 // If the method is a method from Object then defer to normal invocation. 9 if (method.getDeclaringClass() == Object.class) { 10 return method.invoke(this, args); 11 } 12 if (platform.isDefaultMethod(method)) { 13 return platform.invokeDefaultMethod(method, service, proxy, args); 14 } 15 ServiceMethod serviceMethod = loadServiceMethod(method); 16 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); 17 return serviceMethod.callAdapter.adapt(okHttpCall); 18 } 19 }); 20 ......
这里使用到java中高级部分篇章java的动态代理,简单点来说也就是当你调用接口中对应的方法会优先调用InvocationHandler中的invoke方法,有不是很明白的童鞋可行百度了解这块技术,这里就不在深入介绍。
知道动态代理的基本流程,让我们看下invoke方法内部究竟是如何工作的。
2.1、行4,这里根据不同的平台返回不同的Platform platform = Platform.get()对象
2.2、行9-11,这里是判断调用的方式是否是Object里的方法,如果是则直接调用不做处理.
2.3、行12-14,这里仅仅是java8才会使用
2.4、行15,这里还是封装method方法,并且处理对应的注解生成指定的请求头和请求体.
2.5、行16,okHttpCall真正的请求实现类
2.6、行17,返回对应封装了指定数据类型的Call
2.1、精讲说明
1 private static final Platform PLATFORM = findPlatform(); 2 3 static Platform get() { 4 return PLATFORM; 5 } 6 7 private static Platform findPlatform() { 8 try { 9 Class.forName("android.os.Build"); 10 if (Build.VERSION.SDK_INT != 0) { 11 return new Android(); 12 } 13 } catch (ClassNotFoundException ignored) { 14 } 15 try { 16 Class.forName("java.util.Optional"); 17 return new Java8(); 18 } catch (ClassNotFoundException ignored) { 19 } 20 try { 21 Class.forName("org.robovm.apple.foundation.NSObject"); 22 return new ios(); 23 } catch (ClassNotFoundException ignored) { 24 } 25 return new Platform(); 26 }
2.1.1、这里调用Platform的静态方法get(),然后调用方法findPlatform()
2.1.2、方法findPlatform()根据不同的平台返回不同的对象,这里咱们使用的Android,所以返回的是Android对象
Android类对象继承Platform类,源码如下:
1 static class Android extends Platform { 2 @Override public Executor defaultCallbackExecutor() { 3 return new MainThreadExecutor(); 4 } 5 6 @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { 7 return new ExecutorCallAdapterFactory(callbackExecutor); 8 } 9 10 static class MainThreadExecutor implements Executor { 11 private final Handler handler = new Handler(Looper.getMainLooper()); 12 13 @Override public void execute(Runnable r) { 14 handler.post(r); 15 } 16 } 17 }
如上代码可以知道,
1、Android继承自类Platform,重载了Platform方法defaultCallbackExecutor和defaultCallAdapterFactory,方法defaultCallbackExecutor返回一个MainThreadExecutor对象,方法defaultCallAdapterFactory返回了一个对象ExecutorCallAdapterFactory
2、声明静态内部类MainThreadExecutor实现了接口Executor,同时初始化了一个Handler对象。
2.2、精讲说明<判断调用的方式是否是Object里的方法,如果是则直接调用不做处理.>
由于不涉及Retrofit的相关操作,这里不再进行说明。
2.3、精讲说明<这里仅仅是java8才会使用>
为什么这么说那,关键在于代码platform.isDefaultMethod(method),所以想说明白这个问题我们还是需要在进一步看下方法isDefaultMethod,当然前边我说道platform返回的是Android,所以这里先从类Android看。上边说道类Platform重载了Platform方法defaultCallbackExecutor和defaultCallAdapterFactory,所以这里仅仅需要看下platform类对该方法的处理即可。
boolean isDefaultMethod(Method method) { return false; }
默认返回是false,很显然Android平台并不会进入逻辑处理,那么既然说道java8才会使用那么必然java类重载了该方法,深入源码我们看下。
static class Java8 extends Platform { @Override boolean isDefaultMethod(Method method) { return method.isDefault(); } }
正如我们想象的那样。
2.4、精讲说明<这里还是封装method方法,并且处理对应的注解生成指定的请求头和请求体.>
这里我们先跟着代码一起往下看loadServiceMethod(method)
1 ServiceMethod loadServiceMethod(Method method) { 2 ServiceMethod result; 3 synchronized (serviceMethodCache) { 4 result = serviceMethodCache.get(method);//Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>() 5 if (result == null) { 6 result = new ServiceMethod.Builder(this, method).build(); 7 serviceMethodCache.put(method, result); 8 } 9 } 10 return result; 11 }
这里对method和对应的ServiceMethod做了缓存,这里优先判断缓存,如果不存在则去new一个ServiceMethod对象。继续看ServiceMethod对象创建的过程。
类Builder构造器
1 public Builder(Retrofit retrofit, Method method) { 2 this.retrofit = retrofit; 3 this.method = method; 4 this.methodAnnotations = method.getAnnotations(); 5 this.parameterTypes = method.getGenericParameterTypes(); 6 this.parameterAnnotationsArray = method.getParameterAnnotations(); 7 }
待续
以上是关于Android Retrofit源码分析(一边用一边侃)的主要内容,如果未能解决你的问题,请参考以下文章
[Android] Retrofit 源码分析之 ServiceMethod 对象
[Android] Retrofit 源码分析之 ServiceMethod 对象
Android实战----Android Retrofit是怎么将回调函数放到UI线程(主线程)中的(源码分析)