使用
retrofit是最近一款比较火的第三方网络请求框架,使用注解、反射、代理模式等方式构造了整体的框架。
一、retrofit的使用
首先来看一下如何使用retrofit:
1、首先通过构造器模式创建了一个Builder对象,然后传入url地址,添加了Converter工厂,添加了RxJava的适配器工厂,通过build创建了一个Retrofit对象
2、通过retrofit对象,传入我们一个通过注解方式写的网络请求的接口,里面有我们写的网络请求的方法。然后返回一个Api的代理。retrofit通过代理模式,将注解后的内容解析成我们要网络请求传递的参数和数据,然后封装成一个请求的代理对象。
3、最后,调用代理对象的方法。由于retrofit可以非常完美的和Rxjava相结合,所以从下面的代码可以看出,api代理请求以后被在主线程中新建的Action1订阅,如果有数据,刷新列表。
这是RxJava的调用方式
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.google.com")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
Api api = retrofit.create(Api.class);
api.rxBenefits(20, count)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<BaseModel<ArrayList<Benefit>>>() {
@Override
public void call(BaseModel<ArrayList<Benefit>> model) {
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
}
})
;
这是普通的调用方式
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.google.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);
Call<BaseModel<ArrayList<Benefit>>> call = api.defaultBenefits(20, count);
call.enqueue(new Callback<BaseModel<ArrayList<Benefit>>>() {
@Override
public void onResponse(Call<BaseModel<ArrayList<Benefit>>> call, Response<BaseModel<ArrayList<Benefit>>> response) {
}
@Override
public void onFailure(Call<BaseModel<ArrayList<Benefit>>> call, Throwable t) {
}
}
);
}
retrofit主线分析
由于需要在创建Builder时传入平台的信息。所以先来看一下platform,如果在android平台,那么返回Android();如果在Java8平台,那么返回Java8(); 但是还有一个IOS?????????如果都不是,返回一个新的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) {
}
try {
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
return new Platform();
}
看一下Plaform里面有什么,可以看到有Java8,Android,IOS内部类,这些内部类都是继承自Platform类的。
image.png
由于用在Android平台,所以我们只看Android中有些什么,有一个线程池内部内,运行在主线程上。可以获得一个defaultCallAdapterFactory,将线程池对象传了进去。这个等到以后会用到,先不分析这个,只要知道Platform可以拿到线程池和CallAdapterFactory。
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
这个分析完以后,我们来看retrofit的建造者内部类。
public static final class Builder {
// 上面分析的Platform
private Platform platform;
// 目前只支持okhttp,获取okhttp的工厂类
private okhttp3.Call.Factory callFactory;
// 我们设置的Url
private HttpUrl baseUrl;
// 一个converterFactory的List,主要用于将请求内容转化
private List<Converter.Factory> converterFactories = new ArrayList<>();
// 用于包装call的工厂的list
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
// 我们穿进去的线程池
private Executor callbackExecutor;
// 不知道。。。
private boolean validateEagerly;
Builder(Platform platform) {
// 创建Builder时,需要传入平台的信息
this.platform = platform;
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
// 添加一个内置的converter的工厂
converterFactories.add(new BuiltInConverters());
}
public Builder() {
this(Platform.get());
}
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;
}
/** 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) {
adapterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
public Builder callbackExecutor(Executor executor) {
this.callbackExecutor = checkNotNull(executor, "executor == null");
return this;
}
public Builder validateEagerly(boolean validateEagerly) {
this.validateEagerly = validateEagerly;
return this;
}
public Retrofit build() {
// 判断url是否为空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 看是否有传入一个callFactory,如果没有传入,那么就创建一个新的
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 看是否有传入线程池,如果没有传入,创建一个新的,这里看到我们上满分析的Platform类,创建一个运行在主线程的callbackExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 新建calladapter的List,添加platform中默认的factory,这个factory也是我们上面分析到过的,但是具体功能等到下面来分析。主要用于将请求适配成我们需要的Call请求封装对象
// 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));
// 将构造器中的convertfactory List放进去,这个主要用于将请求转换为我们需要的格式
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
// 创建retrofit对象返回
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
分析完构造器,我们再来看一下通过代理模式创建请求接口的对象的代码。源码注释中已经写得比较明白了这个方法的具体作用
@SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
// 首先接茬service是否为一个符合规范的interface,如果不是接口,或者实现了其他接口,则抛出异常
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
// 动态代理,这个retrofit比较关键的部分
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
// 获取Platform对象
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
// 得到目标方法所在类对应的Class对象,如果是Object类,则调用一般的反射
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// 在Android凭条,这个都是false
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 通过反射获得ServiceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
// 获得一个OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 调用CallAdapter中的adapt方法,将okHttpCall转换为我们需要的类型
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
接下来我们对上面三个标黄的方法逐个分析
首先来卡ServiceMethod类,下面这个是Retrofit中的方法。
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
serviceMethodCache是一个非常重要的map,用于保存代理后的方法。
loadServiceMethod也是Retrofit中的方法,首先判断是否已经存在,如果不存在则创建,创建后加入到map中。
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
分析new ServiceMethod.Builder(this, method).build();
在ServiceMethod类中:
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 获取方法上的注解
this.methodAnnotations = method.getAnnotations();
// 方法参数类型的数组
this.parameterTypes = method.getGenericParameterTypes();
// 获取参数的注解的数组
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
(注:getgenericparametertypes)
public type[] getgenericparametertypes()
按照声明顺序返回 type 对象的数组,这些对象描述了此 method 对象所表示的方法的形参类型的。如果底层方法不带参数,则返回长度为 0 的数组。
如果形参类型是参数化类型,则为其返回的 type 对象必须实际反映源代码中使用的实际类型参数。
如果形参类型是类型变量或参数化类型,则创建它。否则将解析它。
返回:
按照声明顺序返回表示底层方法的形参类型的 type 对象数组
建造者构建
public ServiceMethod build() {
// 新建callAdapter
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?");
}
// 新建responseConverter
responseConverter = createResponseConverter();
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);
}
// 解析方法参数注解
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.");
}
// 返回
return new ServiceMethod<>(this);
}
private CallAdapter<?> createCallAdapter() {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
callAdapter中调用的是Retrofit中的代码
/**
* Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
* #callAdapterFactories() factories} except {@code skipPast}.
*
* @throws IllegalArgumentException if no call adapter available for {@code type}.
*/
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
如果是默认的,则调用ExecutorCallAdapterFactory中的get方法,返回的Call最主要的是adapt。adapt方法将一个Call对象传入。我们来看一下传入后返回的是什么
记得创建Retrofit对象时如果不传入CallAdaperFactory,那么会新建ExecutorCallAdapterFactory,新建时将主线程的Executor传入。adapt后的ExecutorCallbackCall中enqueue非常重要,其将在子线程中请求的返回值发布到主线程中,然后是success和fail的方法回调。
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@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(final Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
callback.onFailure(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
最后我们来看一下请求前和请求后对数据进行封装和解析的过程。
在Retrofit进行创建的时候,我们是可以传入一个ConvertorFactory对象的,如最上面的示例。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://gank.io/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
那么我们来看一下GsonConverterFactory里面有什么
/**
* A {@linkplain Converter.Factory converter} which uses Gson for JSON.
* <p>
* Because Gson is so flexible in the types it supports, this converter assumes that it can handle
* all types. If you are mixing JSON serialization with something else (such as protocol buffers),
* you must {@linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this instance}
* last to allow the other converters a chance to see their types.
*/
public final class GsonConverterFactory extends Converter.Factory {
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static GsonConverterFactory create(Gson gson) {
return new GsonConverterFactory(gson);
}
private final Gson gson;
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
}
从源码中可以看到,该类继承自 Converter.Factory,最主要的是responseBodyConverter和requestBodyConverter这两个方法。这两个方法获得请求和相应的转换类,再进去看下转换类里面的内容。发现是一些Gson转换的东西。
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
在ServiceMethod创建时获得了ResponseConverter,该Conveter是从retrofit中获得的
responseConverter = createResponseConverter();
在ServiceMethod的toResponse方法中使用了responseConveter.convert方法。(toResponse方法在OkHttpCall执行请求结束后的parseResponse中调用)
/** Builds a method return value from an HTTP response body. */
T toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
而requestConverter方法则在ServiceMethod中的parseParameterAnnotation方法中调用,获取了retrofit中的Converter对象。
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
到这里,Retrofit的大致框架已经分析完了。如果有机会,RxjavaCallAdapter这个比较重要的部分还没有分析,会再去详细的分析。
源码
github上的源码:
https://github.com/square/retrofit
网友评论