内容简介:本文介绍 Retrofit 网络框架,包含简单的使用和源码解析。Type-safe HTTP client for Android and Java by Square, Inc.前面介绍过 OkHttp ,Retrofit 是对 OkHttp 网络请求框架的封装,前者专注于接口的封装,后者专注于真正的网络请求。
本文介绍 Retrofit 网络框架,包含简单的使用和源码解析。 本文内容基于 Retrofit 2.4.0 版本 。
Type-safe HTTP client for Android and Java by Square, Inc. http://square.github.io/retrofit/
前面介绍过 OkHttp ,Retrofit 是对 OkHttp 网络请求框架的封装,前者专注于接口的封装,后者专注于真正的网络请求。
应用程序通过 Retrofit 请求网络,实际上是由 Retrofit 接口层封装请求参数、Header、Url 等信息,由 OkHttp 完成实际的请求操作;在服务端返回数据后,OkHttp 将原始的结果交给 Retrofit,Retrofit 根据用户的需求对结果进行解析。
Retrofit 的简单使用
参考官网的介绍:
1、创建 HTTP API 接口
public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
2、创建 Retrofit 实例,并实现接口实例
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build(); GitHubService service = retrofit.create(GitHubService.class);
3、创建请求实例
Call<List<Repo>> call = service.listRepos("wshunli");
4、发送网络请求
// 同步请求 call.execute(); // 异步请求 call.enqueue(new Callback<List<Repo>>() { @Override public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) { } @Override public void onFailure(Call<List<Repo>> call, Throwable t) { Log.d(TAG, "onFailure: "); } });
和 OkHttp 流程差不多,特别是发送请求方法名字都没有变。
Retrofit 的源码分析
Retrofit 网络请求完整的流程图如下:
下面详细介绍。
创建 Retrofit 实例
Retrofit 实例化,也是使用的建造者模式。
我们先看 Builder 成员变量的含义:
// Retrofit#Builder public static final class Builder { // 当前系统环境 private final Platform platform; // 网络请求器的工厂 private @Nullable okhttp3.Call.Factory callFactory; // 网络请求地址 private HttpUrl baseUrl; // 数据转换器工厂集合 private final List<Converter.Factory> converterFactories = new ArrayList<>(); // 网络请求适配器工厂集合 private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(); // 回调方法执行器 private @Nullable Executor callbackExecutor; // 标志位 private boolean validateEagerly;
1、首先构造函数中通过 Platform.get()
初始化了平台参数
Builder(Platform platform) { this.platform = platform; } public Builder() { this(Platform.get()); } Builder(Retrofit retrofit) { platform = Platform.get(); callFactory = retrofit.callFactory; baseUrl = retrofit.baseUrl; converterFactories.addAll(retrofit.converterFactories); // Remove the default BuiltInConverters instance added by build(). converterFactories.remove(0); callAdapterFactories.addAll(retrofit.callAdapterFactories); // Remove the default, platform-aware call adapter added by build(). callAdapterFactories.remove(callAdapterFactories.size() - 1); callbackExecutor = retrofit.callbackExecutor; validateEagerly = retrofit.validateEagerly; }
我们可以看下判断方法:
// 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(); } /* 省略部分无关代码 */ }
后面如果有需要,我们也可以直接拷贝。
2、然后设置 Retrofit 所需的参数即可
public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); HttpUrl httpUrl = HttpUrl.parse(baseUrl); if (httpUrl == null) { throw new IllegalArgumentException("Illegal URL: " + baseUrl); } return baseUrl(httpUrl); } public Builder baseUrl(HttpUrl baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); List<String> pathSegments = baseUrl.pathSegments(); if (!"".equals(pathSegments.get(pathSegments.size() - 1))) { throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl); } this.baseUrl = baseUrl; return this; } /** Add converter factory for serialization and deserialization of objects. */ public Builder addConverterFactory(Converter.Factory factory) { converterFactories.add(checkNotNull(factory, "factory == null")); return this; } public Builder addCallAdapterFactory(CallAdapter.Factory factory) { callAdapterFactories.add(checkNotNull(factory, "factory == null")); return this; }
3、最后是 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(); } 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.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size()); // 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); return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
创建 API 实例
获取 API 实例使用 Retrofit 的 create()
方法
// 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(); @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); } ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall); } }); }
创建 API 实例使用的是 动态代理 设计模式。
创建请求实例
创建请求实例,跟钱买你的动态代理有关。
// Retrofit#create() ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.adapt(okHttpCall);
1、 loadServiceMethod()
方法
一个 ServiceMethod
对应于一个 API 接口的一个方法, loadServiceMethod()
方法负责加载 ServiceMethod
// Retrofit#loadServiceMethod() ServiceMethod<?, ?> loadServiceMethod(Method method) { ServiceMethod<?, ?> result = serviceMethodCache.get(method); 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; }
2、 OkHttpCall
类
OkHttpCall
实现了 retrofit2.Call
,我们通常会使用它的 execute()
和 enqueue()
接口。
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) { this.serviceMethod = serviceMethod; this.args = args; }
构造方法也没有什么好看的。
发送网络请求
发送网络请求其实也就是 OkHttpCall
类中的方法。
1、 同步请求 使用 execute()
方法
// OkHttpCall#execute() @Override public Response<T> execute() throws IOException { okhttp3.Call call; synchronized (this) { if (executed) throw new IllegalStateException("Already executed."); executed = true; if (creationFailure != null) { if (creationFailure instanceof IOException) { throw (IOException) creationFailure; } else if (creationFailure instanceof RuntimeException) { throw (RuntimeException) creationFailure; } else { throw (Error) creationFailure; } } call = rawCall; if (call == null) { try { call = rawCall = createRawCall(); } catch (IOException | RuntimeException | Error e) { throwIfFatal(e); // Do not assign a fatal error to creationFailure. creationFailure = e; throw e; } } } if (canceled) { call.cancel(); } return parseResponse(call.execute()); }
这里就是 Retrofit 和 OkHttp 交互的核心了,分为三步:
(1)创建 okhttp3.Call
,包括构造参数
private okhttp3.Call createRawCall() throws IOException { okhttp3.Call call = serviceMethod.toCall(args); if (call == null) { throw new NullPointerException("Call.Factory returned null."); } return call; }
(2)执行网络请求,也就是 OkHttp 的同步网络请求
call.execute()
(3)解析返回的结果
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); // Remove the body's source (the only stateful object) so we can pass the response along. rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); if (code < 200 || code >= 300) { try { // Buffer the entire body to avoid future I/O. ResponseBody bufferedBody = Utils.buffer(rawBody); return Response.error(bufferedBody, rawResponse); } finally { rawBody.close(); } } if (code == 204 || code == 205) { rawBody.close(); return Response.success(null, rawResponse); } ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody); try { T body = serviceMethod.toResponse(catchingBody); return Response.success(body, rawResponse); } catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was // a runtime exception. catchingBody.throwIfCaught(); throw e; } }
2、 异步请求 使用 enqueue()
方法
@Override public void enqueue(final Callback<T> callback) { checkNotNull(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) { callFailure(e); return; } try { callback.onResponse(OkHttpCall.this, response); } catch (Throwable 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) { t.printStackTrace(); } } }); }
我们可以看到和同步请求是一致的,实际请求交给了 okhttp3.Call#enqueue(Callback responseCallback)
来实现,并在它的 callback
中调用 parseResponse()
解析响应数据,并转发给传入的 callback
。
Retrofit 源码就先介绍到这里了,后面有机会再详细介绍。
参考资料
1、Retrofit分析-漂亮的解耦套路 - 简书
https://www.jianshu.com/p/45cb536be2f4
2、Android:手把手带你 深入读懂 Retrofit 2.0 源码 - 简书
https://www.jianshu.com/p/0c055ad46b6c
3、Retrofit源码分析(超详细) - 简书
https://www.jianshu.com/p/097947afddaf
4、拆轮子系列:拆 Retrofit - Piasy的博客 | Piasy Blog
https://blog.piasy.com/2016/06/25/Understand-Retrofit/
5、Retrofit源码解析 | mundane的幻想空间
https://mundane799699.github.io/2018/03/13/retrofit-analysis/
6、Retrofit源码解析 - 掘金
https://juejin.im/post/5acee62c6fb9a028df22ffee
7、Retrofit源码解析 | 俞其荣的博客 | Qirong Yu’s Blog
https://yuqirong.me/2017/08/03/Retrofit源码解析/
8、android-cn/android-open-project-analysis
https://github.com/android-cn/android-open-project-analysis/tree/master/tool-lib/network/retrofit
9、【Android】Retrofit源码分析 - CSDN博客
https://blog.csdn.net/u010983881/article/details/79933220如果本文对您有所帮助,且您手头还很宽裕,欢迎打赏赞助我,以支付网站服务器和域名费用。 您的鼓励与支持是我更新的最大动力,我会铭记于心,倾于博客。
以上所述就是小编给大家介绍的《Retrofit 网络框架源码解析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Vuex 框架原理与源码分析
- Glide 图片加载框架源码解析
- 从框架源码看责任链实现
- Californium开源框架之源码分析(三)
- Californium开源框架之源码分析(四)
- Android开源框架源码分析:Okhttp
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java 8实战
厄马(Raoul-Gabriel Urma)、弗斯科(Mario Fusco)、米克罗夫特(Alan Mycroft) / 陆明刚、劳佳 / 人民邮电出版社 / 2016-4-1 / CNY 79.00
本书全面介绍了Java 8 这个里程碑版本的新特性,包括Lambdas、流和函数式编程。有了函数式的编程特性,可以让代码更简洁,同时也能自动化地利用多核硬件。全书分四个部分:基础知识、函数式数据处理、高效Java 8 编程和超越Java 8,清晰明了地向读者展现了一幅Java 与时俱进的现代化画卷。一起来看看 《Java 8实战》 这本书的介绍吧!