本文介绍 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 成员变量的含义:
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); converterFactories.remove(0 ); callAdapterFactories.addAll(retrofit.callAdapterFactories); callAdapterFactories.remove(callAdapterFactories.size() - 1 ); callbackExecutor = retrofit.callbackExecutor; validateEagerly = retrofit.validateEagerly; }
我们可以看下判断方法:
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 ; } 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(); } List<CallAdapter.Factory> callAdapterFactories = new ArrayList <>(this .callAdapterFactories); callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); List<Converter.Factory> converterFactories = new ArrayList <>(1 + this .converterFactories.size()); converterFactories.add(new BuiltInConverters ()); converterFactories.addAll(this .converterFactories); return new Retrofit (callFactory, baseUrl, unmodifiableList(converterFactories), unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly); }
创建 API 实例 获取 API 实例使用 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 (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 实例使用的是 动态代理 设计模式。
创建请求实例 创建请求实例,跟钱买你的动态代理有关。
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
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() 方法
@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); 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 的同步网络请求
(3)解析返回的结果
Response<T> parseResponse (okhttp3.Response rawResponse) throws IOException { ResponseBody rawBody = rawResponse.body(); rawResponse = rawResponse.newBuilder() .body(new NoContentResponseBody (rawBody.contentType(), rawBody.contentLength())) .build(); int code = rawResponse.code(); if (code < 200 || code >= 300 ) { try { 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) { 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 Bloghttps://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 Bloghttps://yuqirong.me/2017/08/03/Retrofit源码解析/ 8、android-cn/android-open-project-analysishttps://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