retrofit 封装的点
Build 模式 创建网络请求基本配置
用注解来排列组合成网络请求,以不变应万变
统一提供Gson解析,提供了可复用,易拓展的数据解析方案
自定义Executor(handler)完成线程的切换。
什么是Retrofit Retrofit :A type-safe HTTP client for Android and Java。一个类型安全的 Http 请求的客户端。
底层的网络请求是基于 OkHttp 的,Retrofit 对其做了封装,提供了即方便又高效的网络访问框架。
Retrofit的基本用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class RetrofitActivity : AppCompatActivity () { override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) val retrofit = Retrofit.Builder() .baseUrl("https://api.github.com/" ) .addConverterFactory(GsonConverterFactory.create()) .build() val service = retrofit.create(GitHubApiService::class .java) val repos = service.listRepos("octocat" ) repos.enqueue(object : Callback<List<Repo>?> { override fun onFailure ( call: Call <List <Repo >?>, t: Throwable ) { t.printStackTrace() } override fun onResponse ( call: Call <List <Repo >?>, response: Response <List <Repo >?>) { "response.code() = ${response.code()} " .logE() } }) } }
1 2 3 4 5 6 interface GitHubApiService { @GET("users/{user}/repos" ) fun listRepos (@Path("user" ) user: String ?) : Call<List<Repo>> }
源码分析 几个表面上的类:
Retrofit: 总揽全局一个类,一些配置,需要通过其内部 Builder
类构建,比如 CallAdapter、Converter 等
GitHubApiService: 自己写的 API 接口,通过 Retrofit 的 create
方法进行实例化
Call: Retrofit 的 Call,是执行网络请求的是一个顶层接口,需要看源码,具体实现类实际是一个 OkHttpCall
Callback: 请求结果回调
Call 的 enqueue
方法:
1 2 3 4 5 public interface Call extends Cloneable { void enqueue (Callback callback) ; }
这是一个接口,是 GitHubApiService 接口中定义的 listRepos
方法中返回的 Call 对象,现在就要看GitHubApiService 的初始化,以及具体返回的是 Call 对象是谁。
然后重点就要看 retrofit.create(GitHubApiService::class.java)
方法,来看下 GitHubApiService 具体是怎么创建的,以及 Call 对象的实现类
Retrofit的create 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 { if (method.getDeclaringClass() == Object.class) { return method.invoke(this , args); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); }
注释 1:这个方法,就是验证我们定义的 GitHubApiService 是一个接口,且不是泛型接口,并且会判断是否进行方法的 提前验证 ,为了更好的把错误暴露的编译期,
注释 2 :是一个动态代理的方法,来返回 GitHubApiService 的实例
动态代理的示例 写一个动态代理的Demo 下面是一个 Java 项目,模拟一个 Retrofit 的请求过程
1 2 3 4 5 public interface GitHubApiService { void listRepos (String user) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ProxyDemo { public static void main (String[] args) { GitHubApiService apiService = (GitHubApiService) Proxy.newProxyInstance( GitHubApiService.class.getClassLoader(), new Class []{GitHubApiService.class}, new InvocationHandler () { @Override public Object invoke ( Object proxy, Method method, Object[] args) throws Throwable { System.out.println("method = " + method.getName() + " args = " + Arrays.toString(args)); return null ; } }); System.out.println(apiService.getClass()); apiService.listRepos("octcat" ); } }
执行 main
方法
当调用 apiService.listRepos("octcat");
方法时,打印出来如下结果
1 2 class com.sun.proxy.$Proxy0 method = listRepos args = [octcat]
当调用 listRepos
方法的时候,InvocationHandler 的 invoke
方法中拦截到了方法,参数等信息。 Retrofit 的原理其实就是拦截到方法、参数,再根据我们在方法上的注解,去拼接为一个正常的OkHttp 请求,然后执行。
日志的第一行,在运行时这个类一个 $Proxy0
的类。实际上,在运行期 GitHubApiService 的接口会动态的创建出 实现类 也就是这个 $Proxy0
类,它大概长下面这个样子,具体可看从一道面试题开始说起 枚举、动态代理的原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class $Proxy0 extends Proxy implements GitHubApiService { protected $Proxy0(InvocationHandler h) { super (h); } @Override public void listRepos (String user) { Method method = Class.forName("GitHubApiService" ).getMethod("listRepos" , String.class); super .h.invoke(this , method, new Object []{user}); } }
在调用 listRepos
方法的时候,实际上调用的是 InvocationHandler 的 invoke
方法。
总结
在 ProxyDemo 代码运行中,会动态创建 GitHubApiService 接口的实现类,作为代理对象,执行InvocationHandler 的 invoke
方法。
动态指的是在运行期,而代理指的是实现了GitHubApiService 接口的具体类,实现了接口的方法,称之为代理
本质上是在运行期,生成了 GitHubApiService 接口的实现类,调用了 InvocationHandler 的 invoke
方法。
Retrofit.create 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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 { if (method.getDeclaringClass() == Object.class) { return method.invoke(this , args); } args = args != null ? args : emptyArgs; return platform.isDefaultMethod(method) ? platform.invokeDefaultMethod(method, service, proxy, args) : loadServiceMethod(method).invoke(args); } }); }
注释 1:获取一个 ClassLoader 对象
注释 2:GitHubApiService 的字节码对象传到数组中去,也即是我们要代理的具体接口。
注释 3:InvocationHandler 的 invoke
是关键,从上面动态代理的 Demo 中,我们知道,在GitHubApiService声明的 listRepos
方法在调用时,会执行 InvocationHandler 的 invoke
的方法体。
注释 4:因为有代理类的生成,默认继承 Object 类,所以如果是 Object.class 走,默认调用它的方法
注释 5:如果是默认方法(比如 Java8 ),就执行 platform 的默认方法。 否则执行 loadServiceMethod
方法的 invoke
方法
loadServiceMethod 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap <>();ServiceMethod<?> loadServiceMethod(Method method) { 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; }
注释 1:从 ConcurrentHashMap 中取一个 ServiceMethod 如果存在直接返回
注释 2:通过 ServiceMethod.parseAnnotations(this, method);
方法创建一个 ServiceMethod 对象
注释 3:用 Map 把创建的 ServiceMethod 对象缓存起来,因为我们的请求方法可能会调用多次,缓存提升性能。
ServiceMethod.parseAnnotations 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 static <T> ServiceMethod<T> parseAnnotations (Retrofit retrofit, Method method) { ... return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations ( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false ; boolean continuationBodyNullable = false ; okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted <>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse <>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody <>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } }
返回的是一个 HttpServiceMethod 对象
HttpServiceMethod.invoke 1 2 3 4 5 6 7 8 @Override final @Nullable ReturnT invoke (Object[] args) { Call<ResponseT> call = new OkHttpCall <>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); }
OkHttpCall的enqueue方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 @Override public void enqueue (final Callback<T> callback) { Objects.requireNonNull(callback, "callback == null" ); okhttp3.Call call; Throwable failure; synchronized (this ) { if (executed) throw new IllegalStateException ("Already executed." ); executed = true ; call = rawCall; failure = creationFailure; if (call == null && failure == null ) { try { call = rawCall = createRawCall(); } catch (Throwable t) { throwIfFatal(t); failure = creationFailure = t; } } } if (failure != null ) { callback.onFailure(this , failure); return ; } if (canceled) { call.cancel(); } call.enqueue( new okhttp3 .Callback() { @Override public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return ; } try { callback.onResponse(OkHttpCall.this , response); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } @Override public void onFailure (okhttp3.Call call, IOException e) { callFailure(e); } private void callFailure (Throwable e) { try { callback.onFailure(OkHttpCall.this , e); } catch (Throwable t) { throwIfFatal(t); t.printStackTrace(); } } }); }
注释 1:声明一个 okhttp3.Call 对象,用来进行网络请求
注释 2:给 okhttp3.Call 对象进行赋值,下面会具体看代码,如何创建了一个 okhttp3.Call 对象
注释 3:调用 okhttp3.Call 的 enqueue
方法,进行真正的网络请求
注释 4:解析响应,下面会具体看代码
注释 5:成功的回调
注释 6:失败的回调
okhttp3.Call 对象是怎么创建的 看下 call = rawCall = createRawCall();
方法
1 2 3 4 5 6 7 8 9 10 11 private final okhttp3.Call.Factory callFactory;private okhttp3.Call createRawCall () throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null ) { throw new NullPointerException ("Call.Factory returned null." ); } return call; }
通过 callFactory 创建的(callFactory应该是 OkHttpClient),看一下 callFactory 的赋值过程
1 2 3 4 5 6 7 8 9 10 11 12 OkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this .requestFactory = requestFactory; this .args = args; this .callFactory = callFactory; this .responseConverter = responseConverter; }
在 OkHttpCall 构造中直接赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private final okhttp3.Call.Factory callFactory;@Override final @Nullable ReturnT invoke (Object[] args) { Call<ResponseT> call = new OkHttpCall <>(requestFactory, args, callFactory, responseConverter); return adapt(call, args); } HttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { this .requestFactory = requestFactory; this .callFactory = callFactory; this .responseConverter = responseConverter; }
1 static final class CallAdapted extends HttpServiceMethod {}
CallAdapted 是 HttpServiceMethod 的子类,会调用 adapt
方法进行 CallAdapter 的转换,我们后面会详细看。
Builder类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static final class Builder { public Retrofit build () { okhttp3.Call.Factory callFactory = this .callFactory; if (callFactory == null ) { callFactory = new OkHttpClient (); } return new Retrofit ( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); } }
callFactory 实际是一个 OkHttpClient 对象,也就是 OkHttpClient 创建了一个 Call 对象
在创建okhttp3.Call 对象的 callFactory.newCall(requestFactory.create(args));
方法中的 requestFactory.create(args)
方法会返回一个 Request 的对象,这个我们也会在下面看是如何构造一个 OkHttp 的 Request 请求对象的。
请求注解参数是怎么解析的 ServiceMethod.parseAnnotations(this, method)
1 2 3 4 5 6 7 8 static <T> ServiceMethod<T> parseAnnotations (Retrofit retrofit, Method method) { RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); ... return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); }
RequestFactory.parseAnnotations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 final class RequestFactory { static RequestFactory parseAnnotations (Retrofit retrofit, Method method) { return new Builder (retrofit, method).build(); } RequestFactory build () { for (Annotation annotation : methodAnnotations) { parseMethodAnnotation(annotation); } .... return new RequestFactory (this ); } }
遍历 GitHubApiService 这个 API 接口上定义的方法注解,然后解析注解
parseMethodAnnotation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private void parseMethodAnnotation (Annotation annotation) { if (annotation instanceof DELETE) { parseHttpMethodAndPath("DELETE" , ((DELETE) annotation).value(), false ); } else if (annotation instanceof GET) { parseHttpMethodAndPath("GET" , ((GET) annotation).value(), false ); } ... else if (annotation instanceof POST) { parseHttpMethodAndPath("POST" , ((POST) annotation).value(), true ); } .... else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError(method, "Only one encoding annotation is allowed." ); } isMultipart = true ; } else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError(method, "Only one encoding annotation is allowed." ); } isFormEncoded = true ; } }
RequestFactory 这个类还有 parseParameter
和 parseParameterAnnotation
这个就是解析方法参数声明上的具体参数的注解
分析方法上的各个注解,方法参数上的注解,最后返回 RequestFactory 对象,给下面使用。
RequestFactory 对象返回出去,具体干嘛用了? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 static <T> ServiceMethod<T> parseAnnotations (Retrofit retrofit, Method method) { RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); } static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations ( Retrofit retrofit, Method method, RequestFactory requestFactory) { ... okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted <>(requestFactory, callFactory, responseConverter, callAdapter); } .... } CallAdapted( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { super (requestFactory, callFactory, responseConverter); this .callAdapter = callAdapter; } HttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { this .requestFactory = requestFactory; this .callFactory = callFactory; this .responseConverter = responseConverter; } OkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this .requestFactory = requestFactory; this .args = args; this .callFactory = callFactory; this .responseConverter = responseConverter; }
经过层层传递 RequestFactory 这个实例终于是到了 HttpServiceMethod 类中,最终传到了 OkHttpCall 中,那这个 RequestFactory 对象在什么时候使用呢? RequestFactory 会继续在OkHttpCall中传递,因为 OkHttpCall 才是进行请求的。
在OkHttpCall的 创建 Call 对象时
1 2 3 4 5 6 7 8 9 private okhttp3.Call createRawCall () throws IOException { okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null ) { throw new NullPointerException ("Call.Factory returned null." ); } return call; }
注释 1:调用了 requestFactory.create(args)
注意:此时的RequestFactory的各个成员变量在解析注解那一步都赋值了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 okhttp3.Request create (Object[] args) throws IOException { ... RequestBuilder requestBuilder = new RequestBuilder ( httpMethod, baseUrl, relativeUrl, headers, contentType, hasBody, isFormEncoded, isMultipart); ... return requestBuilder.get().tag(Invocation.class, new Invocation (method, argumentList)).build(); }
最终 requestFactory 的值用来构造 okhttp3.Request 的对象
请求响应结果是如何解析的 比如我们在构造 Retrofit 的时候加上 addConverterFactory(GsonConverterFactory.create())
这行代码,我们的响应结果是如何通过 Gson 直接解析成数据模型的?
在 OkHttpCall 的 enqueue
方法中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Override public void enqueue (final Callback<T> callback) { okhttp3.Call call; ... call.enqueue( new okhttp3 .Callback() { @Override public void onResponse (okhttp3.Call call, okhttp3.Response rawResponse) { Response<T> response; try { response = parseResponse(rawResponse); } catch (Throwable e) { throwIfFatal(e); callFailure(e); return ; } } ... }); }
注释 1:通过 parseResponse
解析响应返回给回调接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private final Converter<ResponseBody, T> responseConverter;Response<T> parseResponse (okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); ... ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody (rawBody); try { T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { catchingBody.throwIfCaught(); throw e; } }
注释 1:通过 responseConverter 调用 convert
方法
首先那看 responseConverter 是什么以及赋值的过程,然后再看 convert
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 private final Converter<ResponseBody, T> responseConverter;OkHttpCall( RequestFactory requestFactory, Object[] args, okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) { this .requestFactory = requestFactory; this .args = args; this .callFactory = callFactory; this .responseConverter = responseConverter; } private final Converter<ResponseBody, ResponseT> responseConverter;HttpServiceMethod( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter) { this .requestFactory = requestFactory; this .callFactory = callFactory; this .responseConverter = responseConverter; } CallAdapted( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, ReturnT> callAdapter) { super (requestFactory, callFactory, responseConverter); this .callAdapter = callAdapter; }
继续看 CallAdapted 的初始化中 responseConverter 的赋值过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations ( Retrofit retrofit, Method method, RequestFactory requestFactory) { ... CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted <>(requestFactory, callFactory, responseConverter, callAdapter); } ... }
继续跟代码 createResponseConverter
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter ( Retrofit retrofit, Method method, Type responseType) { Annotation[] annotations = method.getAnnotations(); try { return retrofit.responseBodyConverter(responseType, annotations); } catch (RuntimeException e) { throw methodError(method, e, "Unable to create converter for %s" , responseType); } } final List<Converter.Factory> converterFactories;public <T> Converter<ResponseBody, T> responseBodyConverter (Type type, Annotation[] annotations) { return nextResponseBodyConverter(null , type, annotations); } public <T> Converter<ResponseBody, T> nextResponseBodyConverter ( @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) { ... int start = converterFactories.indexOf(skipPast) + 1 ; for (int i = start, count = converterFactories.size(); i < count; i++) { Converter<ResponseBody, ?> converter = converterFactories.get(i).responseBodyConverter(type, annotations, this ); if (converter != null ) { return (Converter<ResponseBody, T>) converter; } } ... }
注释 1:从 converterFactories 遍历取出一个来调用 responseBodyConverter
方法,注意根据 responseType 返回值类型 来取到对应的 Converter,如果不为空,直接返回此 Converter 对象
converterFactories 这个对象的赋值过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 final List<Converter.Factory> converterFactories;Retrofit( okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this .callFactory = callFactory; this .baseUrl = baseUrl; this .converterFactories = converterFactories; this .callAdapterFactories = callAdapterFactories; this .callbackExecutor = callbackExecutor; this .validateEagerly = validateEagerly; } public Retrofit build () { ... List<Converter.Factory> converterFactories = new ArrayList <>( 1 + this .converterFactories.size() + platform.defaultConverterFactoriesSize()); converterFactories.add(new BuiltInConverters ()); converterFactories.addAll(this .converterFactories); converterFactories.addAll(platform.defaultConverterFactories()); return new Retrofit ( callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
注释 1:初始化 converterFactories 这个 list
注释 2:添加默认的构建的转换器,其实是 StreamingResponseBodyConverter 和 BufferingResponseBodyConverter
注释 3:就是自己添加的转换配置 addConverterFactory(GsonConverterFactory.create())
1 2 3 4 5 public Builder addConverterFactory (Converter.Factory factory) { converterFactories.add(Objects.requireNonNull(factory, "factory == null" )); return this ; }
注释 4:如果是 Java8 就是一个 OptionalConverterFactory 的转换器否则就是一个空的
是怎么找到GsonConverterFactory来调用 Gson 的 convert方法的呢? 在遍历converterFactories时会根据 responseType 来找到对应的转换器。
CallAdapter的替换过程 使用 RxJava 进行网络请求 怎么转成 RxJava
比如:我们在初始化一个Retrofit时加入 addCallAdapterFactory(RxJava2CallAdapterFactory.create())
这行
1 2 3 4 5 6 7 val retrofit = Retrofit.Builder() .baseUrl("https://api.github.com/" ) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build()
加入 RxJava2 的配置支持后,把 RxJava2CallAdapterFactory 存到 callAdapterFactories 这个集合中
1 2 3 4 interface GitHubApiService { @GET("users/{user}/repos" ) fun listReposRx (@Path("user" ) user: String ?) : Single<Repo> }
我们就可以这么请求接口了
1 2 3 4 5 6 7 8 9 10 val service = retrofit.create(GitHubApiService::class.java)service.listReposRx("octocat" ) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ repo -> "response name = ${repo[0].name}" .logE() }, { error -> error.printStackTrace() })
我们可以在自己定义的 API 接口中直接返回一个 RxJava 的 Single 对象的,来进行操作了。
我们下面就来看下是如何把请求对象转换成一个 Single 对象的
1 2 3 4 5 public Builder addCallAdapterFactory (CallAdapter.Factory factory) { callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null" )); return this ; }
把 RxJava2CallAdapterFactory 存到了callAdapterFactories 这个 list 中了。
CallAdapter是如何被赋值过程 HttpServiceMethod的 parseAnnotations
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations ( Retrofit retrofit, Method method, RequestFactory requestFactory) { .... CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted <>(requestFactory, callFactory, responseConverter, callAdapter); } ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter ( Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { try { return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations); } catch (RuntimeException e) { throw methodError(method, e, "Unable to create call adapter for %s" , returnType); } } public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { return nextCallAdapter(null , returnType, annotations); } public CallAdapter<?, ?> nextCallAdapter( @Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) { ... int start = callAdapterFactories.indexOf(skipPast) + 1 ; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this ); if (adapter != null ) { return adapter; } } ... }
遍历 callAdapterFactories 根据 returnType类型 来找到对应的 CallAdapter 返回
比如:我们在 GitHubApiService 的 returnType 类型为 Single,那么返回的就是 RxJava2CallAdapterFactory 所获取的 CallAdapter
1 2 3 4 interface GitHubApiService { @GET("users/{user}/repos") fun listReposRx (@Path("user") user: String?) : Single<Repo> }
RxJava2CallAdapterFactory的 get
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Override public @Nullable CallAdapter<?, ?> get( Type returnType, Annotation[] annotations, Retrofit retrofit) { Class<?> rawType = getRawType(returnType); if (rawType == Completable.class) { return new RxJava2CallAdapter (Void.class, scheduler, isAsync, false , true , false , false , false , true ); } boolean isFlowable = rawType == Flowable.class; boolean isSingle = rawType == Single.class; boolean isMaybe = rawType == Maybe.class; if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) { return null ; } ... return new RxJava2CallAdapter (responseType, scheduler, isAsync, isResult, isBody, isFlowable, isSingle, isMaybe, false ); }
返回的是 RxJava2CallAdapter 对象,并且根据 rawType 判断当前是个什么类型
看下 RxJava2CallAdapter 的 adapt
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Override public Object adapt (Call<R> call) { Observable<Response<R>> responseObservable = isAsync ? new CallEnqueueObservable <>(call) : new CallExecuteObservable <>(call); Observable<?> observable; if (isResult) { observable = new ResultObservable <>(responseObservable); } else if (isBody) { observable = new BodyObservable <>(responseObservable); } else { observable = responseObservable; } if (scheduler != null ) { observable = observable.subscribeOn(scheduler); } if (isFlowable) { return observable.toFlowable(BackpressureStrategy.LATEST); } if (isSingle) { return observable.singleOrError(); } if (isMaybe) { return observable.singleElement(); } if (isCompletable) { return observable.ignoreElements(); } return RxJavaPlugins.onAssembly(observable); }
Retrofit 如何支持 Kotlin 协程的 suspend 挂起函数的? Kotlin 协程请求网络的 Demo 添加依赖
1 2 3 4 5 6 7 def kotlin_coroutines = '1.3.7' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
定义请求接口,写一个挂起函数
1 2 3 4 5 interface GitHubApiService { @GET("users/{user}/repos" ) suspend fun listReposKt (@Path("user" ) user: String ?) : List<Repo> }
请求接口
1 2 3 4 5 6 7 8 9 10 11 12 13 val service = retrofit.create(GitHubApiService::class .java)lifecycleScope.launchWhenResumed { try { val repo = service.listReposKt("octocat" ) "response name = ${repo[0 ].name} " .logE() } catch (e: Exception) { e.printStackTrace() } }
Kotlin 协程的挂起函数的准备工作 1 2 3 suspend fun test (name: String ) {}
我们通过 Android Studio 再带的工具,如下图:把 Kotlin 方法转成 Java 方法
结果如下
1 2 3 4 5 6 public final class SuspendKt { @Nullable public static final Object test (@NotNull String name, @NotNull Continuation $completion) { return Unit.INSTANCE; } }
suspend 的关键字,变成了 test
方法的一个Continuation参数,且为最后一个参数
1 2 3 4 5 @SinceKotlin("1.3" ) public interface Continuation <in T > { public val context: CoroutineContext public fun resumeWith (result: Result <T >) }
Retrofit 是怎么支持 Kotlin 协程的挂起函数的。 最终会调用到 HttpServiceMethod 的 parseAnnotations
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations ( Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false ; boolean continuationBodyNullable = false ; Annotation[] annotations = method.getAnnotations(); Type adapterType; if (isKotlinSuspendFunction) { Type[] parameterTypes = method.getGenericParameterTypes(); Type responseType = Utils.getParameterLowerBound( 0 , (ParameterizedType) parameterTypes[parameterTypes.length - 1 ]); if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) { responseType = Utils.getParameterUpperBound(0 , (ParameterizedType) responseType); continuationWantsResponse = true ; } else { } adapterType = new Utils .ParameterizedTypeImpl(null , Call.class, responseType); annotations = SkipCallbackExecutorImpl.ensurePresent(annotations); } else { adapterType = method.getGenericReturnType(); } Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType); okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { return new CallAdapted <>(requestFactory, callFactory, responseConverter, callAdapter); } else if (continuationWantsResponse) { return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse <>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter); } else { return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody <>( requestFactory, callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter, continuationBodyNullable); } }
注释 1:获取 isKotlinSuspendFunction 的值,这个会在下面具体分析
注释 2:如果是 Kotlin 挂起函数,进入此代码块
注释 3:把 continuationWantsResponse 赋值为 true
注释 4:返回 SuspendForResponse 它是 HttpServiceMethod 的子类,然后看它的 adapt
方法,
requestFactory.isKotlinSuspendFunction 赋值 requestFactory 这个类,是解析注解的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 private @Nullable ParameterHandler<?> parseParameter( int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) { ParameterHandler<?> result = null ; if (annotations != null ) { for (Annotation annotation : annotations) { ParameterHandler<?> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation); if (annotationAction == null ) { continue ; } if (result != null ) { throw parameterError( method, p, "Multiple Retrofit annotations found, only one allowed." ); } result = annotationAction; } } if (result == null ) { if (allowContinuation) { try { if (Utils.getRawType(parameterType) == Continuation.class) { isKotlinSuspendFunction = true ; return null ; } } catch (NoClassDefFoundError ignored) { } } throw parameterError(method, p, "No Retrofit annotation found." ); } return result; }
注释 1:遍历解析参数的注解,就是 @Path @Query @Field 等注解,具体就不看了,不是协程的重点
注释 2:如果是协程 ,其实比的就是最后一个值
注释 3:判断参数类型是 Continuation,这个接口,前面在 10.2 小节写 Demo 时提过
注释 4:isKotlinSuspendFunction 赋值为 true
如果isKotlinSuspendFunction 为 true 时,返回就是 SuspendForResponse 类
SuspendForResponse类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 static final class SuspendForResponse <ResponseT> extends HttpServiceMethod <ResponseT, Object> { private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter; SuspendForResponse( RequestFactory requestFactory, okhttp3.Call.Factory callFactory, Converter<ResponseBody, ResponseT> responseConverter, CallAdapter<ResponseT, Call<ResponseT>> callAdapter) { super (requestFactory, callFactory, responseConverter); this .callAdapter = callAdapter; } @Override protected Object adapt (Call<ResponseT> call, Object[] args) { call = callAdapter.adapt(call); Continuation<Response<ResponseT>> continuation = (Continuation<Response<ResponseT>>) args[args.length - 1 ]; try { return KotlinExtensions.awaitResponse(call, continuation); } catch (Exception e) { return KotlinExtensions.suspendAndThrow(e, continuation); } } }
注释 1:调用 callAdapter 代理 call 方法
注释 2:取出最后一个参数,强转成 Continuation 类型,想想我们写的 Demo
注释 3:Call 的扩展函数(Kotlin 的写法)下面具体看下 awaitResponse
注释 4:出现异常,抛出异常。所以要在代码中,要主动 try catch,来处理错误
Call的扩展函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 suspend fun <T> Call<T> .awaitResponse () : Response<T> { return suspendCancellableCoroutine { continuation -> continuation.invokeOnCancellation { cancel() } enqueue(object : Callback<T> { override fun onResponse (call: Call <T >, response: Response <T >) { continuation.resume(response) } override fun onFailure (call: Call <T >, t: Throwable ) { continuation.resumeWithException(t) } }) } }
注解 注解(Annotation),也叫元数据(Metadata),是Java5的新特性,JDK5引入了Metadata很容易的就能够调用Annotations。注解与类、接口、枚举在同一个层次,并可以应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中,用来对这些元
注解通过反射获取
首先通过 Class 对象的 isAnnotationPresent()方法判断它是否应用了某个注
然后通过 getAnnotation()方法来获取 Annotation 对象
或者是 getAnnotations()方法 返回注解到这个元素上的所有注解
定义该注解的生命周期-@Retention RetentionPolicy.SOURCE:在源文件中有效,被编译器丢弃,用来提示开发者RetentionPolicy.CLASS:在class文件有效,被虚拟机丢弃,用于自动生成代码RetentionPolicy.RUNTIME:运行时有效,常用于自动注入
注解的语法与定义形式
以@interface关键字定义
注解包含成员,成员以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。
成员赋值是通过@Annotation(name=value)的形式。
注解需要标明注解的生命周期,注解的修饰目标等信息,这些信息是通过元注解实现。
1 2 3 4 5 @Retention(value = RetentionPolicy.RUNTIME) @Target(value = { ElementType.ANNOTATION_TYPE } ) public @interface Target { ElementType[] value(); }
元注解@Retention,成员value的值为RetentionPolicy.RUNTIME。
元注解@Target,成员value是个数组,用{}形式赋值,值为ElementType.ANNOTATION_TYPE
成员名称为value,类型为ElementType[]
另外需要注意,如果成员名称是value,在赋值过程中可以简写。如果成员类型为数组,但是只赋值一个元素,则也可以简写。如上面的简写形式为:
1 2 3 4 5 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
注解的运用场景限定 @Documented 标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
1 2 3 4 5 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented {}
@Inherited 标记注解,允许子类继承父类的注解
1 2 3 4 5 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited {}
@Retention 指Annotation被保留的时间长短,标明注解的生命周期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }
1 2 3 4 5 6 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value () ; }
@Target 标明注解的修饰目标,共有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); } public enum ElementType { TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE }
总结 什么是动态代理?
动态 指的是在运行期
代理 指的是实现了某个接口的具体类,称之为代理,会调用了 InvocationHandler 的 invoke
方法。
Retrofit 中的动态代理:
在代码运行中,会动态创建 GitHubApiService 接口的实现类,作为代理对象,代理接口的方法
在我们调用GitHubApiService 接口的实现类的 listRepos
方法时,会调用了 InvocationHandler 的 invoke
方法。
本质上是在运行期,生成了 GitHubApiService 接口的实现类,调用了 InvocationHandler 的 invoke
方法。
动态代理的示例
整个请求的流程是怎样的
在调用 GitHubApiService 接口的 listRepos
方法时,会调用 InvocationHandler 的 invoke
方法
然后执行 loadServiceMethod
方法并返回一个 HttpServiceMethod 对象并调用它的 invoke
方法
然后执行 OkHttpCall的 enqueue
方法
本质执行的是 okhttp3.Call 的 enqueue
方法
当然这期间会解析方法上的注解,方法的参数注解,拼成 okhttp3.Call 需要的 okhttp3.Request 对象
然后通过 Converter 来解析返回的响应数据,并回调 CallBack 接口
底层是如何用 OkHttp 请求的?
OkHttpCall的enqueue方法
方法上的注解是什么时候解析的,怎么解析的?
在 ServiceMethod.parseAnnotations(this, method); 方法中开始的
具体内容是在 RequestFactory 类中,进行解析注解的
调用 RequestFactory.parseAnnotations(retrofit, method); 方法实现的
请求注解参数是怎么解析的
Converter 的转换过程,怎么通过 Gson 转成对应的数据模型的?
通过成功回调的 parseResponse(rawResponse);
方法开始
通过 responseConverter 的 convert
方法
responseConverter 是通过 converterFactories 通过遍历,根据返回值类型来使用对应的 Converter 解析
请求响应结果是如何解析的
CallAdapter 的替换过程,怎么转成 RxJava 进行操作的?
通过配置 addCallAdapterFactory(RxJava2CallAdapterFactory.create()) 在 callAdapterFactories 这个 list 中添加 RxJava2CallAdapterFactory
如果不是 Kotlin 挂起函数最终调用的是 CallAdapted 的 adapt
方法
callAdapter 的实例是通过 callAdapterFactories 这个 list 通过遍历,根据返回值类型来选择合适的CallAdapter
CallAdapter的替换过程
如何支持 Kotlin 协程的 suspend 挂起函数的?
通过 RequestFactory 解析方法上的参数值来判断是不是一个挂起函数,并把 isKotlinSuspendFunction 变量置为 true
根据 isKotlinSuspendFunction 这个变量来判断响应类型是否是 Response 类型,然后把continuationWantsResponse 置为 true
根据 continuationWantsResponse 这个变量,来返回 SuspendForResponse 对象
并调用 SuspendForResponse 的 invoke 方法
通过 Call 的扩展函数,来调用 Call 的 enqueue方法
通过协程来返回