Retrofit是一款针对Android网络请求的框架,它的底层是OKHttp实现的,可以用注解来定义请求的格式。
implementation 'com.squareup.retrofit2:retrofit:2.3.0'//导入retrofit
//支持json类型的格式转换成model
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
首先我们写一个使用Get方式请求的网络接口。
public interface DemoService {
@GET("home?name=prozac")
Call<DemoModel> getAModel();
}
@GET 定义了此请求的方式为Get,参数为访问的地址。返回一个Call
//创建Retrofit对象,设置url,数据转换器
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.demo.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
//通过retrofit.create创建出之前定义的接口对象
DemoService demoService = retrofit.create(DemoService.class);
//获得call对象,调用enqueue进行异步网络请求,传入回调对象操作回调
Call<DemoModel> call = demoService.getDemoModel();
call.enqueue(new Callback<DemoModel>() {
@Override
public void onResponse(Call<DemoModel> call, Response<DemoModel> response) {
//调用response对象的body参数就可以获得自动转换的泛型中类型对象了
DemoModel model = response.body();
}
@Override
public void onFailure(Call<DemoModel> call, Throwable t) {
}
});
使用@Path注解来动态配置url地址。
//传进来的String参数path会取代{path}的位置
@GET("{path}/home?name=prozac")
Call<DemoModel> getDemoModel(@Path("path") String path);
使用@Query注解来动态配置查询参数。
//name参数会在Get请求的url后面自动拼接
@GET("home")
Call<DemoModel> getDemoModel(@Query("name")String name);
使用@QueryMap注解动态配置查询参数数组。
//自动遍历map中的数据并拼接
@GET("home")
Call<DemoModel> getDemoModel(@QueryMap Map<String,String> map);
post请求方式和get请求方式相比需要更改几个注解的名称,改造如下:
//注明表单请求,post请求时必须加上
@FormUrlEncoded
//采用Post注解
@POST("home")
//动态参数时采用的注解为@Field而不是@Query
Call<DemoModel> getDemoModel(@Field("name") String name);
使用@Body注解传输Json格式数据。
//Retrofit会自动将javaBean对象转换成json进行传输
@FormUrlEncoded
@POST("home")
Call<DemoModel> getDemoModel(@Body User user);
有时候我们请求网络的时候需要在消息报头里添加一些额外的信息,用Retrofit可以静态或动态的添加这些信息。
使用@Headers注解静态添加头部信息。
@FormUrlEncoded
@POST("home")
//这里可以添加多条头部信息,如果只需要添加一条可以去掉大括号
@Headers({
"Accept-Encoding:application/json",
"User-Agent:Retrofit"
})
Call<DemoModel> getDemoModel(@Body User user);
使用@Header注册动态添加头部信息
@FormUrlEncoded
@POST("home")
Call<DemoModel> getDemoModel(@Header("Accept-Encoding")String encoding);
接下来看看Retrofit源码里是怎样做的。
Retrofit通过它的Builder进行创建,我们从Builder方法开始看起。
public Builder() {
this(Platform.get());
}
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();
}
下面看看返回Retrofit对象的Build()方法。
public Retrofit build() {
//baseUrl不能为空
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//创建一个OkHttpClient对象
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);
}
这个方法设置了Retrofit的参数,返回了一个配置好的Retrofit对象。
先来看下我们的接口对象是怎么实例化的,也就是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 the method is a method from Object then defer to normal invocation.
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.callAdapter.adapt(okHttpCall);
}
});
}
跟进一下loadServiceMethod,看看对method对象做了什么操作。
ServiceMethod<?, ?> loadServiceMethod(Method method) {
//检查缓存
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//通过Builder.build()创建Call对象,跟进
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
这里检测如果没有生成方法的缓存,则会通过ServiceMethod.Builder去创建一个新的对象。
public ServiceMethod build() {
//这个方法会获取我们之前设置的callAdapter的get方法,如果没设置系统默认设置了一个,为DefaultCallAdapterFactory.get(),代码放下方
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 = createResponseConverter();
//对方法的注解进行解析
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...
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);
}
...
//创建对象并返回
return new ServiceMethod<>(this);
}
//createCallAdapter()会调用到此处的get方法
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
//我们自己定义的实际返回的类型
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
//返回数据类型
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return call;
}
};
}
}
接下来我们回到retrofit.create()方法,看看ServiceMethod被创建之后做了什么操作。
public <T> T create(final Class<T> 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 {
...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
//创建一个OkHttpCall对象,传入serviceMethod,和参数
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//调用之前定义的CallAdapter中的方法,返回Call对象
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
这里我们就创建了接口的代理对象,接下来看看请求时的enqueue方法。
call是一个接口类,这里的实际对象类型为OkHttpCall。
//传一个回调对象进来
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
...
//新建了一个call对象,调用对象的enqueue方法
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//转化成response对象
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
...
private void callSuccess(Response<T> response) {
try {
//调用成功的回调函数
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
接下来看一下okhttp3.Response对象转换成Response对象的方法parseResponse。
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
//获得响应体
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
//移除body字段,以便单独处理相应的状态
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
//根据返回的code调用回调
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
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) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
正常情况下会调用serviceMethod.toResponse方法,来看下具体内容:
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
这里也就是根据我们初始化Retrofit时设置的转换器,去转换body对象,我们设置的转换器是GsonConverterFactory创建的,跟进去看下它的convert方法。
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
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 {
//使用Gson使用body获取一个JsonReader
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
//使用JsonReader,将Json格式数据映射成对象返回
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
转换器转换的过程就是把规范的body内容转换成我们期望的对象返回。关于Retrofit源码的细节分析也就到这
总结一下Retrofit从创建到获取到数据对象的整体过程:
1.使用Retrofit.Builder创建Retrofit对象,可以在Builder里设置baseUrl地址,数据适配器,数据转换器等。
2.创建数据Service,根据格式使用注解创建接口方法。
3.通过Retrofit对象的create方法,可以创建出接口的一个代理对象。
4.在调用代理对象中的方法时,会调用到内部InvocationHandler对象的invoke方法,通过对接口方法注解与参数的解析,封装成一个ServiceMethod,最终放在一个Call对象里进行返回。
5.异步访问时调用call.queue方法,内部通过 okhttp3.Call对象的enqueue方法进行异步执行,数据返回时根据状态码选择回调函数。
6.如果设置了数据转换器,在返回时会将body传入转换器,转换成自定义的泛型类型返回给回调函数。
本篇内容就到这了,如果有不对的地方,欢迎大家指正。