Retrofit2基础使用与解析:从使用步骤深入分析源码
使用步骤
步骤一 添加依赖、权限
dependencies {
compile 'com.squareup.retrofit2:retrofit:2.0.2'
// Retrofit库
compile 'com.squareup.okhttp3:okhttp:3.1.2'
// Okhttp库
}
联网权限:
<uses-permission android:name="android.permission.INTERNET"/>
步骤二 创建接收数据实体类
public class Reception {
...
}
依据服务器返回的数据,建造实体类承载数据
步骤三 创建网络请求接口
public interface GetRequest_Interface {
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> 接口方法();
}
使用注解进行请求方式、参数的设置。
方法的返回值默认使用Call<数据实体类>。(使用RxJava时用Observable<实体类>)
步骤四 创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") // 网络请求基础Url地址
.addConverterFactory(GsonConverterFactory.create()) // 数据解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 网络请求适配器
.build();
步骤五 创建网络请求接口实例
// 创建 网络请求接口 的实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
//对 发送请求 进行封装
Call<Reception> call = request.接口方法名();
调用retrofit.create方法获取请求接口的实体类,调用该实体类方法即可对请求进行封装。
步骤六 发出网络请求
//发送网络请求(异步)
call.enqueue(new Callback<Translation>() {
//请求成功时回调
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
//请求处理,输出结果
response.body().show();
}
//请求失败时候的回调
@Override
public void onFailure(Call<Translation> call, Throwable throwable) {
System.out.println("连接失败");
}
});
// 发送网络请求(同步)
Response<Reception> response = call.execute();
使用生成的call,分别调用enqueue、execute进行异步、同步请求。
步骤七 处理返回的数据
response.body().show();
使用数据response进行数据处理。
逐步骤进行源码分析
步骤四 创建retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://xxx.xxx.xxx/") // 网络请求基础Url地址
.addConverterFactory(GsonConverterFactory.create()) // 数据解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 网络请求适配器
.build();
可以看出实例是使用建造者模式创建的,由用户传入一些基础设置参数后,即可build目标实例
new Retrofit:Retrofit类
深入Retrofit类内部看它的成员,分析作用。
public final class Retrofit {
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory;
final HttpUrl baseUrl;
final List<Converter.Factory> converterFactories;
final List<CallAdapter.Factory> callAdapterFactories;
final @Nullable Executor callbackExecutor;
final boolean validateEagerly;
}
Map<Method, ServiceMethod<?, ?>> serviceMethodCache
:用于存储ServiceMethod,即依据接口生成的网络请求方法。(此处与学习的博客用的数据博客发生变化,我的版本用ConcurrentHashMap,而参考博客版本用的LinkedHashMap)
okhttp3.Call.Factory callFactory
:生成网络请求器的工厂(生产Call)
HttpUrl baseUrl
:网络请求的基础Url地址
List<Converter.Factory> converterFactories
:数据转换器工厂集合(生产Converter)
List<CallAdapter.Factory> callAdapterFactories
:网络请求适配器工厂集合(生产CallAdapter,用于将底层使用的OkHttpCall转换成适应于不同平台的网络请求器)
Executor callbackExecutor
:回调方法执行器
boolean validateEagerly
:标记是否需要提前对接口注解进行验证转换
此处多次使用工厂模式,工厂模式可以自动生成对应对象(产品),用户无需再关心生成过程,可以将心思放到流程开发上。
new Retrofit.Builder():Builder类
成员
public static final class Builder {
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
}
Builder类的成员和Retrofit类是对应的,多了一个platform成员
实例化过程
第一步调用无参构造,内部又调用Builder(Platform platform)
有参构造实现
public Builder() {
this(Platform.get());
}
深入Platform类:
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();
}
借助Java反射完成对当前平台的识别,提供不同的实例,安卓使用返回new Android()
继续深入Android类
static class Android extends Platform
该类是Platform的内部类
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
设置默认的回调方法执行器,主要用于在主、子线程切换,将请求数据返回到主UI线程进行方法回调
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
该默认执行器保存主线程的handler,使用post方法切换到主线程进行回调
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
创建默认网络请求适配器,所需执行器参数,以便后续请求完成后,在对应执行器上回调。
上述流程主要是依据安卓平台进行线程切换以完成子青丘县城完成后到主UI线程的回调。(切换是先由ExecutorCallAdapterFactory获取请求器Call,调用该Call的请求方法内部调用了传入的执行器Executor的回调execute方法)
到此处platform获取完成,再看调用的Builder有参构造方法:
Builder(Platform platform) {
this.platform = platform;
}
将获取的参数设置到Builder内。
至此Builder初始化完成,其内部配置了默认Android平台数据、默认网络请求适配器工厂defaultCallAdapterFactory(用于将默认Call再次封装)、给converterFactories和callAdapterFactories创建容器。
.baseUrl(“”)
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);
}
第一步将字符串参数转换为适合OkHttp的Url格式,将该Url传入下一函数:
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;
}
这一层将Url分段,判断是否以/结尾,若数据合理则记录到Builder的baseUrl成员内。
该方法流程就是将字符串网址转换为合适格式后,进行数据合理判断,再存储起来。
.addConverterFactory(GsonConverterFactory.create())
GsonConverterFactory.create()
Gson数据转换器工厂创建:
public static GsonConverterFactory create() {
return create(new Gson());
}
外部调用无参函数,内部传入Gson实例
public static GsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new GsonConverterFactory(gson);
}
此处依据使用的Gson实例真正返回工厂实例
private GsonConverterFactory(Gson gson) {
this.gson = gson;
}
构造方法就是将Gson对象保存起来
addConverterFactory()
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
将创建的工厂存储到Builder的转换器工厂集合中
剩余工厂参数配置流程基本同此。
.build()
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
baseUrl必须配置好
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
判断是否设置过网络请求执行器工厂,若没设置,采用默认OkHttp进行网络请求
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
判断是否设置过回调执行器,若没设置,采用默认安卓自身的执行器(在platform中实现)
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
将传入的所有适配器工厂参数接收进来, 最后加上系统默认工厂
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
依旧是接收所有配置进来的转换器工厂,先加入系统默认数据转换器BuiltInConverters,再加入配置好的工厂
上述两个列表存储,后续查找使用都是从头遍历找到尾,固越在前面优先级越高。
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
最后调用Retrofit的构造函数生成实例。(unmodifiableList
会使列表数据可以读取,但不能修改)
步骤五 创建网络请求接口实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
Call<Reception> call = request.接口方法名();
retrofit.create()
public<T> T create(final Class<T> service) {
依据传入的接口class对象创建
Utils.validateServiceInterface(service);
此处判断是否是有效接口 方法一
if (validateEagerly) {
eagerlyValidateMethods(service);
}
依据先前提到的boolean对象,判断是否需要提前验证 方法二
上述代码中详细方法解析:
方法一
static <T> void validateServiceInterface(Class<T> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
if (service.getInterfaces().length > 0) {
throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
}
}
判断有效①class对象必须是接口②不可实现多个接口
方法二
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
将接口中非系统默认方法加载起来
接下来是重点代理模式的实现
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 (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
上述是将java、系统默认的方法不需记录直接通过反射调用即可。
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
以上三步是生成服务最重要的部分
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
依据接口种方法的注解生成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();
serviceMethodCache.put(method, result);
}
}
return result;
}
从方法缓存中查找是否加载过相同方法,若没有则采用建造者模式新生成(单例模式)
result = new ServiceMethod.Builder<>(this, method).build();
new ServiceMethod类
final class ServiceMethod<R, T> {
static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
//使用正则判断接口名称、URL是否合法
private final okhttp3.Call.Factory callFactory; //网络请求工厂
private final CallAdapter<R, T> callAdapter; //请求适配器
private final HttpUrl baseUrl; //网络请求基础URL地址
private final Converter<ResponseBody, R> responseConverter; //数据转换器
private final String httpMethod; //网络请求的HTTP方法(GET、POST...)
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;
//依据注解设置参数
private final ParameterHandler<?>[] parameterHandlers;//方法参数处理器,解析API定义时的方法参数,在请求时进行设置
}
该类包含了发出具体网络请求需要的全部内容
.Builder<>(this, method)
Builder类的构造方法:
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();
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);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
遍历方法注解并且进行解析并将其设置入httpMethod(主要获取HTTP网络请求方式,用String保存如GET等)
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);
}
对参数逐个依据注解、类型进行解析,生成handler
return new ServiceMethod<>(this);
}
最后将该方法配置完成即可返回此对象。
方法一 createCallAdapter()
private CallAdapter<T, R> createCallAdapter() {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
try {
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) {
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
读取方法的返回值类型、方法注解生成适配器,该适配器工厂的选取在创建Retrofit实例时用列表存储,此处从前向后挨个使用即可。
方法二 createResponseConverter()
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
原理同方法一获取适配器的过程,依据方法注解,在Retrofit实例的转换器工厂列表选取合适工厂进行生产
至此一个方法解析就完成了,后续在接口代理中将该方法对象加入缓存即可。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
new OkHttpCall<>类
final class OkHttpCall<T> implements Call<T> {
private final ServiceMethod<T, ?> serviceMethod; //该网络请求方法对象,保存所有参数内容等
private final @Nullable Object[] args; //网络请求接口的参数
private volatile boolean canceled;
private @Nullable okhttp3.Call rawCall; //最终实际进行网络请求的类
private @Nullable Throwable creationFailure;
private boolean executed;
}
这一步就是将获取好的方法、传入的参数封装入Call,以便后续请求时直接调用获取
return serviceMethod.adapt(okHttpCall);
最后一步使用适配器将请求器转换为合适版本,此处使用不同适配器是属于装饰模式,内部仍然使用okHttpCall执行网络请求,但在其之上还要有其他操作就依据使用的适配器进行装饰。
至此,retrofit.create就分析完成,即完成了对网络请求接口的配置
Call call = request.接口方法名();
从依据接口生成的request中获取用于网络请求的执行器Call,此处的接口方法会被之前动态代理的invoke拦截,执行其中的内容(即将接口方法进行解析配置)
步骤六 发出网络请求
从基础的OkHttpCall的execute同步请求方法出发:
@Overridepublic Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
} catch (IOException | RuntimeException | Error e) {
throwIfFatal(e); // Do not assign a fatal error to creationFailure.
creationFailure = e;
throw e;
}
}
}
return parseResponse(call.execute());
}
首先这个Call的生成是在上一步调用方法时产生,看似调用了方法,实际被动态代理拦截,生成一个Call对象,内部包含了该方法的ServiceMethod对象和所需参数。
接着就是上述代码,首先查看Call是否内部Call是否生成,若没生成则同步锁生成一个createRawCall
方法一
最后使用生成的内部Call执行请求并且解析返回数据 方法二。
方法一 createRawCall()
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = serviceMethod.toCall(args);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
使用之前生成的serviceMethod(包含所有请求所需内容),依据传入参数生成发起请求使用的Call(生成了一个HTTP request)。
方法二 parseResponse(call.execute())
由生成的内部call(request)发起请求并且解析数据。
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
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) {
catchingBody.throwIfCaught();
throw e;
}
}
数据处理首先对response进行解析
①状态码检查,依据不同状态码即可知道该请求的情况,进行相应处理
②当请求成功,会将body传入serviceMethod中,使用之前的设置好的数据转换器将其转换为所需数据类型,再调用Response.success,返回一个完整response
异步请求call.enqueue:
call.enqueue(new Callback<Translation>() {
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
response.body().show();
}
@Override
public void onFailure(Call<Translation> call, Throwable throwable) {
System.out.println("连接失败");
}
});
请求的同步异步是相对于当前线程,并非任务的同步异步,进行同步请求通常将手动创建线程进行网络请求(否则将直接在主UI线程进行请求,阻塞),异步自动创建并执行,最后调回主线程进行数据处理。
异步请求采用静态代理模式,用户写好请求数据的处理后,等请求完成回到主线程直接进行方法回调。
@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);
}
});
}
});
}
源码可以看出异步请求是使用静态代理delegate进行的 分析一
callbackExecutor.execute()
将最后的结果用执行器切换到主线程进行数据处理(安卓的默认执行器就是主线程执行器,是在先前platform中获取到的) 分析二
分析一 静态代理
@Override public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
先前静态代理执行的enqueue实际还是调用了OkHttpCall内部的enqueue(内部流程与同步相同,先查看内部call/request是否生成,生产call并进行调用),在okhttp基础上以静态代理模式添加了线程切换操作。
至此整个流程全部完成。
后面的execute、enqueue都是解析的ExecutorCallbackCall,而不是OkHttpCall,因为在创建retrofit实例时,其中适配器的排序是将系统默认适配器排到了第一位,而安卓默认适配器就是ExecutorCallbackCallAdapter,所以一切业务层对call进行的调用都在对ExecutorCallbackCall的方法调用。