对于现在Android最流行的网络框架Retrofit,我相信用的同学应该很多,但是我们不应该只停留在用这一层上,而应该针对这个框架有个原理上的理解,最起码要读下源码知道是怎么实现的,然后在学习下架构,用的设计模式,对于以后自己的架构能力还是会很有帮助的。我分析的肯定不如大牛分析的好,但是我在努力,如果有不对的地方请留言指出。
先从Retrofit的创建开始吧:
Retroft在创建时,使用的是建造者模式通过Builder进行创建实例。那么先看下这个Builder,是一个在Retrofit中的静态内部类。而Builder提供了创建Retrofit所需参数的方法:
我们在new Retrofit.Builder()时调用的方法为:
Builder(Platform platform) { this.platform = platform; converterFactories.add(new BuiltInConverters()); } public Builder() { this(Platform.get()); }
在这说一下Platform时一个什么东西:Platform通过单词我们就可以知道他是一个平台。来看下这个Platform.get()做了些什么?
static Platform get() { return PLATFORM; }
其实这就是一个Platform的实例:
private static final Platform PLATFORM = findPlatform();
再看下这个findPlatform:
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(); }
在这可以看出Retrofit支持两个平台:Android 和Java8
看下Android平台下的代码:
// 用于接收服务器返回数据后进行线程切换在主线程显示结果
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 该执行器作用:切换线程(子->>主线程),并在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
// 创建默认的网络请求适配器工厂
// 该默认工厂生产的 adapter 会使得Call在异步调用时在指定的 Executor 上执行回调
// 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、
//GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory// 采用了策略模
if (callbackExecutor == null)
throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {/
/ 获取与Android 主线程绑定的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
// 该Handler是上面获取的与Android 主线程绑定的Handler
// 在UI线程进行对网络请求返回数据处理等操作。
handler.post(r);
}
}// 切换线程的流程:
// 1. 回调ExecutorCallAdapterFactory生成了一个ExecutorCallbackCall对象
//2. 通过调用ExecutorCallbackCall.enqueue(CallBack)从而调用MainThreadExecutor的execute()通过handler切换到主线程
}
public Builder client(OkHttpClient client) { return callFactory(checkNotNull(client, "client == null")); } public Builder callFactory(okhttp3.Call.Factory factory) { this.callFactory = checkNotNull(factory, "factory == null"); return this; } 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) { adapterFactories.add(checkNotNull(factory, "factory == null")); return this; } public Builder callbackExecutor(Executor executor) { this.callbackExecutor = checkNotNull(executor, "executor == null"); return this; }
- client:网络请求的用的什么,默认是Okhttp
baseUrl
:网络请求的url地址callFactory
:网络请求工厂adapterFactories
:网络请求适配器工厂的集合converterFactories
:数据转换器工厂的集合callbackExecutor
:回调方法执行器
然后在调用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> adapterFactories = new ArrayList<>(this.adapterFactories); adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor)); // Make a defensive copy of the converters. List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories); return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories, callbackExecutor, validateEagerly); }
把这些设置好的参数用于new Retrofit()对象:
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl, List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories, @Nullable Executor callbackExecutor, boolean validateEagerly) { this.callFactory = callFactory; this.baseUrl = baseUrl; this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site. this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site. this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly; }
这时候我们在Builder中配置的内容就都赋值给这个Retrofit了。到此Retrofit创建完毕。
下面我就分析这个Retrofit在使用时,如果将一个接口方法,转换成一个okHttp请求的。
这是一个接口方法:
public interface NetworkAPI { @GET("v2/movie/subject/{id}") Call<People> getMovieDetail(@Path("id") String id); }
我们在使用时,要先有个Network的对象,但在Java中接口不能直接创建对象,但可以通过代理创建对象。Retrofit时通过Retrofit.create(NetworkAPI.class);来返回一个NetworkAPI对象的,上源码:
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. //这个地方是用于处理java类的代理 if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } //这个地方返回的永远是个false,在Platform中就是返回false if (platform.isDefaultMethod(method)) { return platform.invokeDefaultMethod(method, service, proxy, args); } //这个地方就是把我们借口中的方法转换成一个ServiceMethod对象 ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method); //通过ServiceMethod创建和方法的参数创建一个OkHttpCalldui'xin OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args); return serviceMethod.callAdapter.adapt(okHttpCall); } }); }
我们来看下loadServiceMethod的代码:
ServiceMethod<?, ?> loadServiceMethod(Method method) { //这个地方先判断缓存中是否有这个方法,如果有直接返回 ServiceMethod<?, ?> result = serviceMethodCache.get(method); if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { //这个地方通过ServiceMethod.Builder创建一个ServiceMethod result = new ServiceMethod.Builder<>(this, method).build(); //这是放入缓存 serviceMethodCache.put(method, result); } } return result; }
我们来看下这个ServiceMethod到底是个什么东西:
Adapts an invocation of an interface method into an HTTP call
//将接口执行的方法适配成一个Http请求
这是ServiceMethod的注释。
final class ServiceMethod<R, T> { //网络请求工厂 final okhttp3.Call.Factory callFactory; //网络请求适配器工厂 final CallAdapter<R, T> callAdapter; //网络请求地址 private final HttpUrl baseUrl; //Response内容转换器 //负责把服务器返回的数据转换成T的类型 private final Converter<ResponseBody, R> responseConverter; //网络请求的Http方法 private final String httpMethod; private final String relativeUrl;//网络请求的相对地址 private final Headers headers;//Http请求的请求头,键值对 private final MediaType contentType;//网络请求Http报文body的类型 private final boolean hasBody; private final boolean isFormEncoded; private final boolean isMultipart; //方法参数处理器 //作用:负责解析API定义时每个方法的参数,并在构造HTTP请求时设置参数 private final ParameterHandler<?>[] parameterHandlers; //ServiceMethod 的构造方法,通过Builder传入 ServiceMethod(Builder<R, T> builder) { this.callFactory = builder.retrofit.callFactory(); this.callAdapter = builder.callAdapter; this.baseUrl = builder.retrofit.baseUrl(); this.responseConverter = builder.responseConverter; this.httpMethod = builder.httpMethod; this.relativeUrl = builder.relativeUrl; this.headers = builder.headers; this.contentType = builder.contentType; this.hasBody = builder.hasBody; this.isFormEncoded = builder.isFormEncoded; this.isMultipart = builder.isMultipart; this.parameterHandlers = builder.parameterHandlers; }
下面看下ServiceMethod.build()方法
//作用:控制ServiceMethod对象的生成流程
public ServiceMethod build() {
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
callAdapter = createCallAdapter();
/ 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型
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?");
}
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的数据转换器 -->关注点3
// 构造 HTTP 请求时,我们传递的参数都是String
// Retrofit 类提供 converter把传递的参数都转化为 String
// 其余类型的参数都利用 Converter.Factory 的stringConverter 进行转换
// @Body 和 @Part 类型的参数利用Converter.Factory 提供的 requestBodyConverter 进行转换
// 这三种 converter 都是通过“询问”工厂列表进行提供,而工厂列表我们可以在构造 Retrofit 对象时进行添加。
responseConverter = createResponseConverter();
// 解析网络请求接口中方法的注解
// 主要是解析获取Http请求的方法
// 注解包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded
// 处理主要是调用方法 parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
// 获取当前方法的参数数量
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);
}
// 为方法中的每个参数创建一个ParameterHandler<?>对象并解析每个参数使用的注解类型
// 该对象的创建过程就是对方法参数中注解进行解析
// 这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
<-- 总结 -->
// 1. 根据返回值类型和方法标注从Retrofit对象的的网络请求适配器工厂集合和内容转换器工厂集合中分别获取到该方法对应的网络请求适配器和Response内容转换器;
// 2. 根据方法的标注对ServiceMethod的域进行赋值
// 3. 最后为每个方法的参数的标注进行解析,获得一个ParameterHandler<?>对象
// 该对象保存有一个Request内容转换器——根据参数的类型从Retrofit的内容转换器工厂集合中获取一个Request内容转换器或者一个String内容转换器。
return new ServiceMethod<>(this);
}
接着上面的来说:
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
根据配置好的ServiceMethod和方法参数创建OkHttpCall对象。
最后一步:将第二步创建的OkHttpCall
对象传给第一步创建的serviceMethod
对象中对应的网络请求适配器工厂的adapt()
return serviceMethod.callAdapter.adapt(okHttpCall)