本篇文章分析一下Retrofit结合RxJava2和Gson的使用的时候,CallAdapterFactory和ConverterFactory是如何起作用的。
使用k780api,获取现在的天气信息。
我们请求的格式是json,返回的数据结构
{
"success": "1",
"result": {
"weaid": "1",
"days": "2018-09-13",
"week": "星期四",
"cityno": "beijing",
"citynm": "北京",
"cityid": "101010100",
"temperature": "29℃/20℃",
"temperature_curr": "22℃",
"humidity": "82%",
"aqi": "93",
"weather": "多云",
"weather_curr": "阴",
"weather_icon": "http://api.k780.com/upload/weather/d/2.gif",
"weather_icon1": "",
"wind": "风",
"winp": "0级",
"temp_high": "29",
"temp_low": "20",
"temp_curr": "22",
"humi_high": "0",
"humi_low": "0",
"weatid": "3",
"weatid1": "",
"windid": "423",
"winpid": "207",
"weather_iconid": "2"
}
}
可以使用GsonFormat生成对应的Java文件。
定义请求方法
public interface API {
@FormUrlEncoded
@POST("/")
Observable<NowWeatherBean> getNowWeather(@FieldMap Map<String, Object> map);
}
使用方式
private static final String BASE_URL = "http://api.k780.com";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
//注释1处,添加CallAdapterFactory
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()
//注释2处,添加ConverterFactory
.addConverterFactory(GsonConverterFactory.create())
.build();
//注释3处,创建API的动态代理
API api = retrofit.create(API.class);
HashMap<String, Object> map = new HashMap<>();
map.put("app", "weather.today");
map.put("weaid", 1);
map.put("appkey", 10003);
map.put("sign", "b59bc3ef6191eb9f747dd4e83c99f2a4");
map.put("format", "json");
api.getNowWeather(map)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<NowWeatherBean>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(NowWeatherBean bean) {
Log.e(TAG, "onNext: " + bean.getResult().toString());
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: " + e.getMessage());
}
@Override
public void onComplete() {
}
});
注释1处,添加了一个CallAdapter.Factory对象
RxJava2CallAdapterFactory的create方法
public static RxJava2CallAdapterFactory create() {
//注意传入的参数
return new RxJava2CallAdapterFactory(null, false);
}
RxJava2CallAdapterFactory的构造函数
private RxJava2CallAdapterFactory(Scheduler scheduler, boolean isAsync) {
this.scheduler = scheduler;
this.isAsync = isAsync;
}
在注释2处,添加了一个Converter.Factory对象。
GsonConverterFactory的create方法
public static GsonConverterFactory create() {
return create(new Gson());
}
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new GsonConverterFactory(gson);
}
GsonConverterFactory的构造函数
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
注释3处,调用了Retrofit的create方法,创建API的动态代理。
Retrofit的create方法
public <T> T create(final Class<T> service) {
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
//...
//注释1处
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//注释2处
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//注释3处,将OkHttpCall 适配成我们想要的请求类型
return serviceMethod.adapt(okHttpCall);
}
});
}
public ServiceMethod build() {
//创建CallAdapter
callAdapter = createCallAdapter();
//创建Converter<ResponseBody, T> responseConverter
responseConverter = createResponseConverter();
//解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//方法参数注解数组的长度,注意parameterAnnotationsArray是一个二维数组
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
//遍历解析方法的每个参数的注解
for (int p = 0; p < parameterCount; p++) {
//获取对应的参数类型
Type parameterType = parameterTypes[p];
//获取每个参数的注解数组(每个参数可以有多个注解,但是只能有一个Retrofit注解)
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
//为parameterHandlers赋值
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
//...
return new ServiceMethod<>(this);
}
注释1处,构造ServiceMethod对象
- 创建CallAdapter
- 创建Converter<ResponseBody, T> responseConverter
- 解析方法注解 parseMethodAnnotation
- 解析方法参数注解,创建parameterHandlers
ServiceMethod创建CallAdapter
构建ServiceMethod对象的时候,会遍历Retrofit的callAdapterFactories,根据(我们在接口中定义的)方法的返回类型和注解,返回合适的CallAdapter。现在我们的方法返回类型是Observable<NowWeatherBean>。在Android平台下,默认的CallAdapter只能处理retrofit2.Call<T>
这种返回类型,所以要从我们添加的RxJava2CallAdapterFactory中获取CallAdapter。
看一下RxJava2CallAdapterFactory这个类的get方法
public final class RxJava2CallAdapterFactory extends CallAdapter.Factory {
//获取CallAdapter
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit) {
//returnType是泛型类型Observable<NowWeatherBean>
//rawType是Observable
Class<?> rawType = getRawType(returnType);
//...
boolean isResult = false;
boolean isBody = false;
Type responseType;
//...
//获取的observableType是NowWeatherBean
Type observableType = getParameterUpperBound(0, (ParameterizedType) returnType);
Class<?> rawObservableType = getRawType(observableType);
if (rawObservableType == Response.class) {//条件不满足
} else if (rawObservableType == Result.class) {//条件不满足
} else {
//最终responseType就是NowWeatherBean
responseType = observableType;
isBody = true;
}
//返回一个RxJava2CallAdapter对象
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult,
isBody, isFlowable, isSingle, isMaybe, false);
}
}
方法返回了一个RxJava2CallAdapter对象。
final class RxJava2CallAdapter<R> implements CallAdapter<R, Object> {
//传入的参数注意一下
RxJava2CallAdapter(Type responseType, @Nullable Scheduler scheduler,
boolean isAsync, boolean isResult, boolean isBody, boolean isFlowable,
boolean isSingle, boolean isMaybe, boolean isCompletable) {
this.responseType = responseType;//NowWeatherBean
this.scheduler = scheduler;//null
this.isAsync = isAsync;//false
this.isResult = isResult;//false
this.isBody = isBody;//true
this.isFlowable = isFlowable;//false
this.isSingle = isSingle;//false
this.isMaybe = isMaybe;//false
this.isCompletable = isCompletable;//false
}
@Override public Type responseType() {
//注释1处,NowWeatherBean
return responseType;
}
@Override public Object adapt(Call<R> call) {
//传入的isAsync是false,responseObservable取值是CallExecuteObservable
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable;
if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {//传入的isBody是true
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
}
//这里还能指定线程
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
//注释2处,使用一个CallExecuteObservable对象构建一个BodyObservable对象
return observable;
}
}
在注释1处,RxJava2CallAdapter的responseType方法返回的类型就是NowWeatherBean。
在注释2处,RxJava2CallAdapter的adapt方法会把一个OkHttpCall对象转换成了一个BodyObservable对象。
ServiceMethod创建ResponseBodyConverter
构建ServiceMethod对象的时候,会遍历Retrofit的converterFactories,根据callAdapter的responseType方法返回的类型信息,返回合适的responseBodyConverter。现在responseType是NowWeatherBean,因为在Android平台下,默认的responseBodyConverter只能处理okhttp3.ResponseBody
类型和Void
类型。所以要从我们添加的GsonConverterFactory中获取responseBodyConverter。
public final class GsonConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations,Retrofit retrofit) {
//我们传入的Type是NowWeatherBean
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//返回GsonResponseBodyConverter
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);
}
}
GsonConverterFactory的responseBodyConverter方法返回了一个GsonResponseBodyConverter对象。
顺便提一句,在这个例子中,GsonConverterFactory的requestBodyConverter方法没有被调用。GsonConverterFactory的requestBodyConverter方法返回的GsonRequestBodyConverter对象,用来把okhttp3.RequestBody
类型的请求体转化成合适的类型。我们先不去关注这问题,继续往下看。
GsonResponseBodyConverter类
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 {
//从ResponseBody中获取字符流,然后转化成我们想要的对象,这里就是NowWeatherBean对象。
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
T result = adapter.read(jsonReader);
if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
return result;
} finally {
value.close();
}
}
}
GsonResponseBodyConverter的convert方法会把okhttp3.ResponseBody
类型的响应体,转化成我们希望的数据类型,在这个例子中就是NowWeatherBean。
ServiceMethod解析方法注解 parseMethodAnnotation
//解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
ServiceMethod.Builder的parseMethodAnnotation方法
private void parseMethodAnnotation(Annotation annotation) {
//...
if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof FormUrlEncoded) {
//...
isFormEncoded = true;
}
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
//...
this.httpMethod = httpMethod;
this.hasBody = hasBody;
//注解值为空,直接返回,我们注解中传入的是 "/"
if (value.isEmpty()) {
return;
}
//...
//获取相对路径,
this.relativeUrl = value;
//...
}
ServiceMethod解析方法参数注解,创建parameterHandlers
我们的方法参数注解只有一个@FieldMap
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
//parameterType是Map<String, Object>
Type parameterType = parameterTypes[p];
//...
//parameterAnnotations是[@FieldMap]
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
//...
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
ServiceMethod.Builder的parseParameter方法
private ParameterHandler<?> parseParameter(int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
//遍历解析Retrofit参数注解数组
for (Annotation annotation : annotations) {
//调用parseParameterAnnotation方法
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
result = annotationAction;
}
//...
return result;
}
ServiceMethod.Builder的parseParameterAnnotation方法
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
//...
else if (annotation instanceof FieldMap) {
//rawParameterType 类型是Map类型
Class<?> rawParameterType = Utils.getRawType(type);
//mapType是Map<String, Object>
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
ParameterizedType parameterizedType = (ParameterizedType) mapType;
//keyType是String
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
//valueType是Object
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
//注释1处,valueType是Object
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
gotField = true;
//查找valueConverter,最后返回ParameterHandler.FieldMap对象
return new ParameterHandler.FieldMap<>(valueConverter, ((FieldMap) annotation).encoded());
}
}
我们看一下上面方法的注释1处
//注释1处,valueType是Object
Converter<?, String> valueConverter = retrofit.stringConverter(valueType, annotations);
Retrofit的stringConverter方法
public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
for (int i = 0, count = converterFactories.size(); i < count; i++) {
Converter<?, String> converter =
converterFactories.get(i).stringConverter(type, annotations, this);
if (converter != null) {
return (Converter<T, String>) converter;
}
}
// 没有匹配的Converter,求助于默认转换器,它只调用toString()。
return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
}
无论是Retrofit内置的BuiltInConverters,还是我们添加的GsonConverterFactory,这两个对象都没有重写Converter.Factory的stringConverter方法,所以它俩的stringConverter方法返回的都是null。所以Retrofit的stringConverter方法最终返回的是一个BuiltInConverters.ToStringConverter对象。
static final class ToStringConverter implements Converter<Object, String> {
static final ToStringConverter INSTANCE = new ToStringConverter();
@Override public String convert(Object value) {
return value.toString();
}
}
ToStringConverter的convert方法返回的Object的toString方法的返回值。
在这个例子中,ServiceMethod类创建的parameterHandlers 就是一个ParameterHandler.FieldMap实例。ParameterHandler.FieldMap类的apply方法内部就是把我们的map参数中的value值都转化成String,然后添加到RequestBuilder 中。
ParameterHandler.FieldMap类的apply方法精简版
@Override
void apply(RequestBuilder builder, Map<String, T> value) throws IOException {
//...
for (Map.Entry<String, T> entry : value.entrySet()) {
String entryKey = entry.getKey();
T entryValue = entry.getValue();
//valueConverter就是ToStringConverter对象
String fieldEntry = valueConverter.convert(entryValue);
//注释1处,加入RequestBuilder,以键值对的方式,构建我们的表单提交请求体
builder.addFormField(entryKey, fieldEntry, encoded);
}
}
注释1处,调用RequestBuilder的addFormField方法
void addFormField(String name, String value, boolean encoded) {
if (encoded) {
formBuilder.addEncoded(name, value);
} else {
//默认是不加密的
formBuilder.add(name, value);
}
}
调用FormBody.Builder的add方法
public Builder add(String name, String value) {
private final List<String> names = new ArrayList<>();
private final List<String> values = new ArrayList<>();
names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, false, false, true, true, charset));
values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, false, false, true, true, charset));
return this;
}
可以看到内部就是以键值对的方式,构建我们的表单提交请求体。
2.构建OkHttpCall实例。
3. 返回最后经过serviceMethod转换后的对象。
return serviceMethod.adapt(okHttpCall);
T adapt(Call<R> call) {
return callAdapter.adapt(call);
}
经过上面的分析,我们知道ServiceMethod的callAdapter就是RxJava2CallAdapter。RxJava2CallAdapter的adapt方法把一个OkHttpCall对象转换成了一个BodyObservable对象。
当我们订阅的时候,会调用BodyObservable的subscribeActual方法。
//方法中的参数observer就是我们的订阅者,方法内部把我们的observer包装成了一个BodyObserver对象
@Override protected void subscribeActual(Observer<? super T> observer) {
upstream.subscribe(new BodyObserver<T>(observer));
}
我们从传入BodyObservable的upstream是一个CallExecuteObservable对象
CallExecuteObservable类精简版
final class CallExecuteObservable<T> extends Observable<Response<T>> {
private final Call<T> originalCall;
CallExecuteObservable(Call<T> originalCall) {
this.originalCall = originalCall;
}
@Override
protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
//...
//调用传入的OkHttpCall的execute方法,并调用传入的BodyObserver的onNext方法
Response<T> response = call.execute();
if (!disposable.isDisposed()) {
//调用观察者BodyObserver的onNext方法
observer.onNext(response);
}
}
}
OkHttpCall的execute方法精简版
public Response<T> execute() throws IOException {
okhttp3.Call call;
//注释1处,创建一个请求
call = rawCall = createRawCall();
//注释2处,获取执行结果,并将结果转换成期望的类型
return parseResponse(call.execute());
}
OkHttpCall的createRawCall方法精简版
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
return call;
}
ServiceMethod的toCall方法
okhttp3.Call toCall(@Nullable Object... args) throws IOException {
//注释1处,RequestBuilder 用来构建我们的请求
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl,
headers, contentType, hasBody, isFormEncoded, isMultipart);
//这里的handlers长度是1 ,里面是一个ParameterHandler.FieldMap对象
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
//...
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
callFactory是一个OkHttpClient实例
return callFactory.newCall(requestBuilder.build());
}
ServiceMethod的createRawCall()的过程,就是使用ServiceMethod解析方法注解获取的信息和ServiceMethod创建的parameterHandlers解析出来的方法参数信息构建一个okhttp3.Request实例,在这个例子中,我们的请求体是一个FormBody
对象。然后使用OkHttpClient创建一个okhttp3.RealCall实例。
RequestBuilder的build方法
Request build() {
HttpUrl url;
url = baseUrl.resolve(relativeUrl);
RequestBody body = this.body;
if (body == null) {
// 我们是表单提交,此条件满足
if (formBuilder != null) {
//返回的是一个okhttp3.FormBody对象
body = formBuilder.build();
}
}
//返回一个okhttp3.Request对象
return requestBuilder
.url(url)
.method(method, body)
.build();
}
现在我们的请求准备好了,开始执行,并转换执行结果了。
//注释2处,获取执行结果,并将结果转换成期望的类型
return parseResponse(call.execute());
执行的过程我们就不看了。我们看一下处理响应结果的过程。
OkHttpCall的parseResponse方法
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
//调用ServiceMethod的toResponse方法
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
}
ServiceMethod的toResponse方法
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
在这个例子中,ServiceMethod的responseConverter就是GsonResponseBodyConverter类的实例,GsonResponseBodyConverter的 convert方法从ResponseBody中获取字符流,然后转化成我们想要的对象,这里就是NowWeatherBean对象。所以OkHttpCall的parseResponse方法最后返回的是一个响应体为NowWeatherBean类型的的retrofit2.Response对象。
我们回到CallExecuteObservable的subscribeActual()方法
@Override
protected void subscribeActual(Observer<? super Response<T>> observer) {
// Since Call is a one-shot type, clone it for each new observer.
Call<T> call = originalCall.clone();
//...
//这里的response 就是Response<NowWeatherBean>类型的对象了。
Response<T> response = call.execute();
if (!disposable.isDisposed()) {
//调用observer.onNext()方法
observer.onNext(response);
}
}
然后我们回到BodyObservable的subscribeActual()方法
//方法中的参数observer就是我们的订阅者,方法内部把我们的observer包装成了一个BodyObserver对象
@Override
protected void subscribeActual(Observer<? super T> observer) {
upstream.subscribe(new BodyObserver<T>(observer));
}
BodyObserver是BodyObservable的内部类,BodyObserver就是把我们真正的observer做了一层包装而已。BodyObserver这个名字很好,一看就知道,只关注响应体。看一下BodyObserver的精简版。
private static class BodyObserver<R> implements Observer<Response<R>> {
private final Observer<? super R> observer;
//参数中的observer使我们真正的订阅对象
BodyObserver(Observer<? super R> observer) {
this.observer = observer;
}
@Override
public void onNext(Response<R> response) {
//最终调用我们的observer的onNext()方法,response.body就是NowWeatherBean类的实例。
observer.onNext(response.body());
}
}
}
结束。如果以后有时间会画一个流程图出来,不过感觉可能不会画了,哈哈。本篇文章以一个例子,结合前两篇,梳理了Retrofit的通常使用的场景。Retrofit的学习暂时告一段落。在后续的学习和研究中,会不断改正文章中的错误,完善理解不到位的地方。后续的打算是看看《图解HTTP》这本书,和《RxJava2.x实战》这两本书,并学习RxJava2的相关源码。