Retrofit
retrofit是什么
- 一个 RestFul 的 http 网络请求框架 (是对Okhttp的封装)
- 网络请求的工作本质上是
OkHttp
完成,而 Retrofit 仅负责 网络请求接口的封装
retrofit 为什么存在
-
为了优化okhttp 请求框架的使用
-
在okhttp 相关部分讲过 okhttp 的使用
- 其存在如下几个问题
- 每一个请求须手动创建request,并获取call ,
- 没有自动线程切换
- 得到的response 需手动解析
- 其存在如下几个问题
-
而在retrofit 中
-
开发人员不用考虑okhttp相关的request ,call 创建获取,
Retrofit将 Http请求 抽象成 Java接口
只需要通过注解配置好网络请求的url 和参数,由retrofit 以动态代理的形式通过CallAdapter来生 成retrofit 可用的Call 对象(此时的Call调用enqueue 又会在这里生成okhttp的call ,最终调用的还是okhttp的Call对象的enqueue的方法)
-
得到的response 也可以通过添加的ConverterFactory转换成对应的实体类无需手动解析
-
-
Retrofit 作用
- 为网络请求提供Call 对象(优化从构建request到得到Call对象的过程),并转换为retrofit可用的Call 对象
- 通过添加的ConvertFactory 对okhttp 请求返回的resposne 进行解析
- 内部完成了线程切换 通过handler 调用了 hander.post(runnable) 方法
Retrofit 使用过程 - 表层
-
可以分为以下几步
-
构建Retrofit对象
-
Retrofit retrofit = new Retrofit.Builder(). baseUrl("https://www.test.cn/"). addConverterFactory(GsonConverterFactory.create()). addCallAdapterFactory(RxJavaCallAdapterFactory.create()). build();
-
上面通过Builder.build()构建了retrofit 对象并设置其属性,下面看Builder内部分代码和build方法
-
//网络工厂 即okhttpclient 可知内部网络请求还是okhttp执行的 private okhttp3.Call.Factory callFactory; //网络请求baseurl private HttpUrl baseUrl; //数据类型转换工厂集合 private List<Converter.Factory> converterFactories = new ArrayList<>(); //适配器工厂集合 private List<CallAdapter.Factory> adapterFactories = new ArrayList<>(); //callbackExecutor 也就是在这里执行的 线程切换 将子线程转换到主线程 private Executor callbackExecutor; public Retrofit build() { // 检查baseurl 是否为空 为空抛出异常 if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } //检查CallFactory 是否为空 为空则默认添加一个OkhttpClient okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { callFactory = new OkHttpClient(); } // 创建回调执行器 用来进行线程切换 Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } // 创建适配器的集合,并添加默认的Call适配器。这里即使不设置CallAdapter 也会添加一个默认的 // 这就是为什么我们主动添加CallAdapter 仍能转换为Call的原因 List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // 创建转换器集合 List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); // 创建retrofit return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); }
-
可知在构建Retrofit的时 配置了retrofit 的各项属性 为空的则添加默认值
-
-
创建用于描述网络请求的接口
-
public interface MyService { @GET("users/{user}/repos") Call<String> getParams(); }
-
-
创建网络请求接口实例
-
MyService service = retrofit.create(MyService.class);
-
-
获取Call对象调用网络请求
-
service.getParams().enqueue(new Callback<String>() { @Override public void onResponse(Call<String> call, Response<String> response) { } @Override public void onFailure(Call<String> call, Throwable t) { } });
-
此时线程已经切换回了主线程 至于如何切换的后面会提到
-
-
Retrofit 详细流程
- 上面我们了解retrofit的作用
-
- 为网络请求提供Call 对象(开发人员无需手动构建request 和 call )
-
- 将网络请求的结果response解析进行类型转换
-
- 进行线程切换
-
retrofit 怎么封装的Call对象
-
说到这里 首先从上面的流程中我们知道到得到Call对象我们经历了以下几步
-
- 构建retrofit
- 创建用于请求的接口
- 通过retrofit.create方法创建网络请求接口的代理类
- 通过代理类获取call 对象
-
其实前面两步没啥可说的 就是创建了一个Retrofit 创建了一个接口,第三步还有点能说的,重点在retrofit.create() 方法内 下面我们看下create 方法内做了什么
-
public <T> T create(final Class<T> service) { // 调用 Proxy.newProxyInstance 得到 MyService的代理对象 return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, //这个参数是一个实现了InvocationHandler接口的中介类用做“调用处理器”,当我们调用代理类对象的方法时,这个“调用”会转送到invoke方法中, //这里直接用用了匿名类的写法 new InvocationHandler() { private final Platform platform = Platform.get(); // 重写了invoke方法,当代理对象调用其内部方法时 实际上是通过改中介类的invoke方法调用的 @Override public Object invoke(Object proxy, Method method, Object... args) throws Throwable { if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } //加载ServiceMethod ServiceMethod serviceMethod = loadServiceMethod(method); // 通过serviceMethod创建一个OkhttpCall 这个OkhttpCall 是retrofit自己封装的,不是Okhttp里面的Call OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args); // 通过Adapter.adapt 返回一个 Call 对象 return serviceMethod.callAdapter.adapt(okHttpCall); } });
- ServiceMethod是什么
- (官翻)将接口方法的调用调整为HTTP调用的类。
- 其内部维护一个retrofit 和 method 并存储了该
- 我们看下loadServiceMethod内做了什么
ServiceMethod loadServiceMethod(Method method) { ServiceMethod result; synchronized (serviceMethodCache) { // 从缓存中获取method对应的ServiceMethod对象 若没有则创建一个并放到缓存里 result = serviceMethodCache.get(method); if (result == null) { result = new ServiceMethod.Builder(this, method).build(); serviceMethodCache.put(method, result); } } return result; }
-
loadServiceMethod方法
-
从缓存中获取method对应的ServiceMethod对象 若没有则创建一个并放到缓存里
-
通过Builder 传递一个retrofit 和method 构建了一个ServiceMethod
-
下面我们看这里做了什么
-
ServiceMethod.Builder(retrofit, method).build() public Builder(Retrofit retrofit, Method method) { this.retrofit = retrofit; this.method = method; this.methodAnnotations = method.getAnnotations(); this.parameterTypes = method.getGenericParameterTypes(); this.parameterAnnotationsArray = method.getParameterAnnotations(); } public ServiceMethod build() { //1. 根据方法的返回类型和注解,从retrofit实例中获取CallAapter对象。 就是获取构建retrofit时设置的适配器 callAdapter = createCallAdapter(); 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?"); } //2. 获取response的转换器就是获取构建retrofit 时设置的转换器 responseConverter = createResponseConverter(); // 遍历注解 for (Annotation annotation : methodAnnotations) { // 解析注解 parseMethodAnnotation(annotation); } //````` 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); } //````返回 ServiceMethod return new ServiceMethod<>(this); }
- 代码可知
- ServiceMethod在构建时就已将传递进去的method 的注解,各项信息解析并保存在了当前ServiceMethod对象里
- 获取了根据类型和注解获取了CallAdapter
- 获取了类型转换器
- 代码可知
-
-
-
继续向下执行
- 通过methodService创建了okhttpCall对象
- 通过CallAdapter.adapt 获取可用于网络请求的Call
- ServiceMethod是什么
-
总结
- 由上可知 从得到可用于网络请求的Call 经历如下步骤
-
调用retrofit.create 方法,
-
通过动态代理获取代理类对象
-
通过代理类对象调用其内部的方法时其实调用中介类的invoke 方法得到一个Call对象,invoke方法内部执行了如下步骤
-
构建一个ServieMethod 对象
-
通过 ServieMethod 创建一个OkhttpCall
-
通过CallAdapter.adapt 的到一个代理类对象方法所对应的Call对象(这里还是Retrofit的自己封装的Call,在执行该Call时才会转换为Okhttp的Call)
- 注
这里的call 仅是retrofit 可用的call 真正执行网络请求之前还要转换成okhttp可用的Call 才行
-
-
Retrofit 如何进行的网络请求
-
上面我们知道retrofit 如何获取的Call对象
-
当我们获取到Call对象之后 即可进行网络请求
-
call.enqueue 调用 enqueue 方法即可
-
此时先执行到ExecutorCallbackCall中的enqueue 我们看enqueue 内部
-
@Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("callback == null"); delegate.enqueue(new Callback<T>() { @Override public void onResponse(Call<T> call, final Response<T> response) { //5 注意此处 之这里就是完成 子线程转主线程 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); } }); } }); }
-
我们可以看到 内部通过delegate又调用了enqueue
-
delegate 是Call 对象
-
这次是到了okhttpcall中的enqueue
-
@Override public void enqueue(final Callback<T> callback) { if (callback == null) throw new NullPointerException("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 { // 1 创建真正可用于网络请求的Call Okhttp的Call对象 call = rawCall = createRawCall(); } catch (Throwable t) { failure = creationFailure = t; } } } if (failure != null) { callback.onFailure(this, failure); return; } if (canceled) { call.cancel(); } // 2 通过Okhttp 的Call 对象调用enqueue 执行异步网络请求 call.enqueue(new okhttp3.Callback() { @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) throws IOException { Response<T> response; try { // 3 解析response response = parseResponse(rawResponse); } catch (Throwable e) { callFailure(e); return; } // 4 通过回调将结果回传给ExecutorCallbackCall callSuccess(response); } @Override public void onFailure(okhttp3.Call call, IOException e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callFailure(Throwable e) { try { callback.onFailure(OkHttpCall.this, e); } catch (Throwable t) { t.printStackTrace(); } } private void callSuccess(Response<T> response) { try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable t) { t.printStackTrace(); } } }); }
-
-
-
-
总结
- 由上面代码可知 调用enqueue 执行如下过程
- 1 首先调用enqueue 方法生成Okhttp 的Call对象
- 2 call对象执行网络请求
- 3 解析respnse
- 4 通过回调 讲结果传递出去
- 5 ExecutorCallbackCall 中将回调结果进行线程切换
- 因为是回调 执行结束才能拿到值 所以代码顺序 5 在1,2,3,4 之前
- 由上面代码可知 调用enqueue 执行如下过程
Retrofit 如何进行线程切换
-
在上面步骤中我们知道了在
ExecutorCallbackCall.enqueue
的callBack
中,retrofit
通过callbackExecutor.execute
将response
转换到了主线程 -
那他是如何转换的呢
-
首先这里的
callbackExecutor
是在retrofit 的构建中赋值的-
public Retrofit build() { Executor callbackExecutor = this.callbackExecutor; if (callbackExecutor == null) { callbackExecutor = platform.defaultCallbackExecutor(); } return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); }
-
可以看到 通过
platform.defaultCallbackExecutor();
-
platform 是一个平台 支持Android 和 java 在这里我们是安卓平台
-
platform 在builder里面创建
-
public Builder() { this(Platform.get()); } 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) { } return new Platform(); }
-
这里返回的是安卓
-
-
-
defaultCallbackExecutor 也就是Andorid.defaultCallbackExecutor
-
static class Android extends Platform { // 生成默认的 Executor @Override public Executor defaultCallbackExecutor() { return new MainThreadExecutor(); } // 生成默认的 CallAdapterFactory @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) { 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); } } }
- 由上代码可知
- 生成默认的 Executor 也就是 MainThreadExecutor
- MainThreadExecutor内部维护了一个Handler
- execute方法内部通过Handler.post 完成了线程切换
- 所以callbackExecutor.execute 即 MainThreadExecutor.execute
- 内部通过handler 完成线程切换
- 生成默认的 CallAdapterFactory
-
-
-
-
总结
- retrofit 实质上是对okhttp的封装,隐藏生成request 和call 的实现,完成了线程切换,使用起来更方便,实际上网络请求还是通过okhttp完成的
- 其内部使用了很多设计模式
- 门面模式 比如retrofit .create 只需要传递进去接口class 即可 无需关心内部实现
- 动态代理模式 获取接口文件的代理对象
- builder 模式 创建retorfit对象
- 适配器模式,通过CallAdapter.adapt 返回Call对象
- 流程就不画了描述一下吧
- 创建retrofit对象
- 创建用于描述网络请求的接口文件
- 调用retrofit.create 通过动态代理获取接口文件的代理类proxy
- proxy调用内部方法 通过调用中介类的invoke方法获取Call对象
- 构建MethodService对象
- 通过MethodService创建OkHttpCall
- 通过CallAdapter.adapt 得到Call对象
- 通过Call对象调用enqueue方法传进去CallBack 用于处理结果
- 将OkhttpCall 转换成 okhttp的call对象
- call 执行网络请求 获取response
- 解析response 调用类型转换器转换
- 通过回调返回结果
- callbackExecuter.execute 进行线程切换
- 得到结果进行操作 至此流程结束