Android Retrofit理解
一、对Retrofit的理解
Retrofit底层依赖OkHttp请求网络,是一个RESTful的HTTP网络请求框架的封装,简单理解成封装了OkHttp即可,通过请求参数等方式向服务端请求数据,Retrofit会根据返回数据进行解析。
二、特点
- 支持同步、异步
- 通过注解配置请求(请求头,方法、返回值)
- 通过converter将获得的数据解析和序列化
- 支持Gson、Jackson、Protobuf等
- 支持RxJava
- 性能好,速度快
- 拓展性差,因为使用的converter都是统一的
三、简明使用
配置和注解使用这里不详述,在参考文章里面都有,这里仅仅对我写过的例子进行解析。
//这里我使用的彩云天气的api,因此需要提交GET请求获得天气数据,解析返回数据
public interface PlaceService {
@GET("v2/place?token={token}=zh_CN")//注解表明为get请求,值为相对url
Call<PlaceResponse> searchPlaces(@Query("query")String query);//指定返回数据类型,在下面会配置解析器,这里需要提前根据json数据格式,创建对应的数据类型
}
//构建retrofit对象,设置一些配置项
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://baseUrl/")//baseUrl
.addConverterFactory(GsonConverterFactory.create())//设置请求参数和请求结果的数据转换,通常我们可以使用retrofit提供的Gson解析,这里api返回的是json数据,因此这样设置
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//设置返回类型的解析器,retrofit默认提供的是一个Call对象,可以直接发起请求,我们也可以使用其提供的RXJava的解析器,使其可以返回Observable对象进行链式调用请求,下面会细说
.build();//builder模式构建
RequestService requestService = retrofit.create(PlaceService.class);//通过retrofit的动态代理,创建请求接口对象
Call<DataModel> call = requestService.getData("v1");//调用请求的代理对象的相应方法,传入参数,生成Call对象
call.enqueue(new Callback<DataModel>() {//使用Call对象enqueue发起异步请求,并设置回调
@Override
public void onResponse(Call<DataModel> call, Response<DataModel> response) {//请求成功
DataModel model = response.body();
//success
}
@Override
public void onFailure(Call<BookSearchModel> call, Throwable t) {//请求失败
//failed
}
});
call.cancel();//取消掉请求:回调不会再调用,socket连接被终止
四、 参数配置
- CallFactory
CallFactory是请求所用的客户端,默认为OkHttpClient,但可自定义。 - ConverterFactory
转换请求的参数和请求回来的数据,此类通过工厂模式构建出converter,提供转换的方法。
public interface Converter<F, T> {
T convert(F value) throws IOException;//F转换为T
abstract class Factory {//工厂模式
//提供将ResponseBody转换的Converter
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
//提供将params转换为RequestBody的Converter
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
}
}
//retrofit提供的用gson转换的ConverterFactory
public final class GsonConverterFactory extends Converter.Factory {
...
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
...
}
//retrofit提供的用gson转换ResponseBody的Converter
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
...
@Override public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
return adapter.read(jsonReader);
}
}
看得出其实就是定义convert,在factory的两个方法中用convert来解析数据。
- CallAdapterFactory
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;//实际的OkHttpCall对象
}
@Override public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {//异步发起请求
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {//回调结果
@Override public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
}
常规返回的是Call对象,当想使用RXJava时,可以通过CallAdapterFactory,生成CallAdapter对象,封装原始的OkHttpCall对象为想要的返回类型,retrofit提供的是Cal对象的CallAdapter。
- CallbackExecutor
当异步请求结束返回数据时,需要将数据放到主线程中,因此需要回调callback,Retrofit提供了executor来回调callback,默认提供的是回调主线程的Executor。
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);//回调到主线程中
}
}
Retrofit的create
前面配置完retrofit对象,这时就需要使用create创建了
public <T> T create(final Class<T> service) {
...
//创建动态代理对象返回
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);//根据这个method对象,解析生成ServiceMethod对象,其保存请求方法解析出来的url、params等各种参数
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);//构建OkHttpCall对象,保存serviceMethod和传入的参数,用户请求时生成完整的请求对象
return serviceMethod.callAdapter.adapt(okHttpCall);//调用ServiceMethod中根据method的返回类型生成的CallAdapter的adapt方法,将OkHttpCall对象包装成相应类型返回
}
});
}
这里就是返回了代理对象,代理对象里面有两个成员变量值得关注:ServiceMethod、OkHttpCall。
每当我们调用接口对象某个请求方法时,代理到invoke方法,参数包含调用的方法method对象,以及传入的各种参数。
ServiceMethod对象用于解析method各种注解、参数类型、返回类型,根据这些生成相应的CallAdapter和Converter等。
至于OkHttpCall对象,传入ServiceMethod对象和调用的参数,结合两者生成完整的request对象,交给OkHttp发起请求;
最后调用ServiceMethod中,由对应的CallAdapter的adapt方法,将OkHttpCall对象包装成需要的类型返回。
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();//否则通过builder模式创建一个ServiceMethod对象,并放入缓存
serviceMethodCache.put(method, result);
}
}
return result;
}
前面提到了调用ServiceMethod,通过loadServiceMethod获取对应的method对象,并使用缓存机制,有则直接取出,无则创建并放入缓存,避免重复重建。
ServiceMethod的build
//创建时拿到各种注解
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();//方法上的注解
this.parameterTypes = method.getGenericParameterTypes();//参数的类型
this.parameterAnnotationsArray = method.getParameterAnnotations();//参数上的注解
}
//build构建
public ServiceMethod build() {
callAdapter = createCallAdapter();//根据method的返回类型,去retrofit里注册的CallAdapter里依次去找,找到可以处理的CallAdapter即可
responseType = callAdapter.responseType();//CallAdapter返回类型,这里指的其实是泛型类型,即Call<DataModel>时指的是实际请求的数据类型DataModel
...
responseConverter = createResponseConverter();//根据responseType生成转换ResponseBody的Converter对象
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);//根据方法签名上的注解,解析出相应的请求类型等值,如url、headers、请求方法、是否为富文本等信息
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];//参数处理器,用于将注解等应用到实际参数上生成RequestBody
for (int p = 0; p < parameterCount; p ) {
Type parameterType = parameterTypes[p];//第p个参数类型
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];//第p个参数的所有注解
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);//生成Handler
}
...
return new ServiceMethod<>(this);
}
主要是获取注解、参数、参数转换器convert、返回类型转换call adapter
生成request对象
Request toRequest(Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);//使用已经解析出来的基本参数创建RequestBuilder对象
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
int argumentCount = args != null ? args.length : 0;
for (int p = 0; p < argumentCount; p ) {
handlers[p].apply(requestBuilder, args[p]);//每个ParameterHandler对RequestBuilder应用arg参数
}
return requestBuilder.build();//构建Request对象,内部使用OkHttp的Request.Builder构建出Request对象
}
//比如处理@Body的ParameterHandler.Body
static final class Body<T> extends ParameterHandler<T> {
private final Converter<T, RequestBody> converter;
Body(Converter<T, RequestBody> converter) {
this.converter = converter;
}
@Override void apply(RequestBuilder builder, T value) {
RequestBody body;
...
body = converter.convert(value);//使用converter转换arg为相应类型
...
builder.setBody(body);//设置到RequestBuilder里
}
}
省流:添加参数到handlers中,并通过convert转换为响应类型,最后组装成所需request对象,response同理。
OkHttpCall
final class OkHttpCall<T> implements Call<T> {
...
OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {//保存了ServiceMethod对象和实际参数args
this.serviceMethod = serviceMethod;
this.args = args;
}
@Override public void enqueue(final Callback<T> callback) {//异步发起请求
okhttp3.Call call;
...
call = rawCall = createRawCall();//创建OkHttp的call对象
...
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
response = parseResponse(rawResponse);//转换response
callSuccess(response);//回调callback
}
...
private void callSuccess(Response<T> response) {
callback.onResponse(OkHttpCall.this, response);//回调callback
}
});
}
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);//这步是关键,使用serviceMethod结合(应用)args,生成完整的Request对象
okhttp3.Call call = serviceMethod.callFactory.newCall(request);//使用retrofit配置的CallFactory(OkHttpClient)执行request对象,生成OkHttp的call对象
...
return call;
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
...
int code = rawResponse.code();
if (code < 200 || code >= 300) {//请求成功/失败
...
}
...
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);//包装responseBody
...
T body = serviceMethod.toResponse(catchingBody);//这步也是关键,使用ServiceMethod对象,将原始的ResponseBody转换为我们想要的(返回值泛型类型)类型数据
return Response.success(body, rawResponse);
}
}
构建Request对象,通过CallFactory构建Call对象,通过Call对象发起请求,监听回调,将返回的数据进行解析,将解析后的结果返回。
Cancel
//OkHttpCall.cancel()
public void cancel() {
canceled = true;//标志位置为true,请求还未发送时则不会发送了
okhttp3.Call call;
synchronized (this) {
call = rawCall;
}
if (call != null) {
call.cancel();//关闭OkHttp的call对象,包括socket连接
}
}
//默认的代理类ExecutorCallbackCall.cancel
delegate.enqueue(new Callback<T>() {
@Override public void onResponse(Call<T> call, final Response<T> response) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
if (delegate.isCanceled()) {//如果已经被cancel掉则会模拟当作请求失败,调用onFailure,而不会调用onResponse
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override public void onFailure(Call<T> call, final Throwable t) {
...
}
});
使用callback时,一般需要使用静态内部类 弱引用,避免内存泄漏和防止如当界面销毁时,回调方法里面还持有与界面相关的变量。
五、RXJava
RXJavaCallAdapter
//CallAdapterFactory
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
public static RxJavaCallAdapterFactory create() {//请求时使用当前线程发起请求,即调用call.execute
return new RxJavaCallAdapterFactory(null, false);
}
public static RxJavaCallAdapterFactory createAsync() {//请求时使用异步发起请求,即调用call.enqueue
return new RxJavaCallAdapterFactory(null, true);
}
public static RxJavaCallAdapterFactory createWithScheduler(Scheduler scheduler) {//请求时使用自定义的线程策略,即调用subscribeOn设置指定shcedulers
return new RxJavaCallAdapterFactory(scheduler, false);
}
private final Scheduler scheduler;
private final boolean isAsync;
private RxJavaCallAdapterFactory(Scheduler scheduler, boolean isAsync) {
this.scheduler = scheduler;
this.isAsync = isAsync;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
...
if (rawType != Observable.class && !isSingle && !isCompletable) {//处理类型为Observable的返回值类型
return null;
}
...
return new RxJavaCallAdapter(responseType, scheduler, isAsync, isResult, isBody, isSingle,
false);
}
}
提供了三种策略了启动RXJavaCallAdapterFactory,并可通过get返回对应的CallAdapter。
RXJavaCallAdapter
//adapt方法包装OkHttpCall对象
@Override public Object adapt(Call<R> call) {
//根据是否异步请求创建不同的OnSubscribe对象包装call
OnSubscribe<Response<R>> callFunc = isAsync
? new CallEnqueueOnSubscribe<>(call)
: new CallExecuteOnSubscribe<>(call);
...
Observable<?> observable = Observable.create(func);//创建Observable对象
//设置schedulers的话设置subscribeOn
if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
}
...
return observable;
}
//执行异步请求的CallEnqueueOnSubscribe
final class CallEnqueueOnSubscribe<T> implements OnSubscribe<Response<T>> {
private final Call<T> originalCall;
CallEnqueueOnSubscribe(Call<T> originalCall) {
this.originalCall = originalCall;//原始call对象
}
@Override public void call(Subscriber<? super Response<T>> subscriber) {
Call<T> call = originalCall.clone();
...
call.enqueue(new Callback<T>() {//使用异步发起请求
...//回调subscriber
});
}
}
通过adapt方法返回Observe对象,其封装了原始Call对象。
六、参考
Android Retrofit 原理解析
死磕Android_Retrofit 原理解析
由浅入深剖析Retrofit原理,收好了!!!
Carson带你学Android:这是一份详细的 Retrofit使用教程(含实例讲解)
Android Retrofit详解
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfkccb
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13