1、基本介绍:
1.1、重要类介绍:
call:
- 创建Http网络请求。
- 提供了同步异步请求方法:execute()、enqueue()。
- 生成Request对象,返回请求结果对象。
callFactory:
- Call的工厂类。
- 默认直接new OkHttpClient()。
- 如果你需要对okhttpclient进行详细的设置,需要构建OkHttpClient对象,然后传入。
CallAdapter:
- 网络请求适配器:用于对Call进行转化,将默认的OkHttpCall转换为适合被不同平台来调用的网络请求执行器形式。
- retrofit会通过运行时的不同平台,然后选择不同的CallAdapter。
- 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory。
- 该默认ExecutorCallAdapterFactory会使得Call在异步调用时在指定的 Executor线程上执行回调。
callAdapterFactories:
- CallAdapter的工厂。
callbackExecutor:【切换线程】
- 回调方法执行器:用来将回调传递到UI线程了【利用了Handler机制】。
converterFactories:【对数据对象进行转换】
- 数据转换器工厂,该对象用于转化数据(可用于对请求数据、响应数据、注解参数数据进行转换)
- responseBodyConverter():完成ResponseBody到实际的返回类型的转化。
- requestBodyConverter ():完成对象到RequestBody的构造。
- 一定要注意,检查type如果不是自己能处理的类型,记得return null (因为可以添加多个,你不能处理return null ,还会去遍历后面的converter).
ServiceMethod类:
- 一个 ServiceMethod 对象对应于网络请求接口里的一个方法,用于将我们接口中的方法转化为一个Request对象。
2、具体流程:
2.1、 Retrofit的实例构建:【建造者模式】
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(请求地址)
.addConverterFactory(GsonConverterFactory.create()) //添加数据转换器
.build();
public Builder() {
//查看当前的运行平台,支持Android、Java8平台
this(Platform.get());
}
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//用来将回调传递到UI线程
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//将网络请求对象Call进行平台适配。
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.adapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//数据转化器
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
2.2、retrofit.create()来构建Call对象:【动态代理模式】
GitHubService service =??retrofit.create(GitHubService.class);
retrofit.Call<返回实体> call= service.请求的接口名称(请求参数);
【Retrofit.java】
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
// 判断是否需要提前验证:
1. 给接口中每个方法的注解进行解析并得到一个ServiceMethod对象.
2. 以Method为键将该对象存入LinkedHashMap集合中.
3. 特别注意:如果不是提前验证则进行动态解析对应方法,得到一个ServiceMethod对象,最后存入到LinkedHashMap集合中,类似延迟加载(默认)
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.adapt(okHttpCall);
}
});
}
• 根据我们的method将其包装成ServiceMethod.
• 通过ServiceMethod和方法的参数构造retrofit2.OkHttpCall对象。
• 通过serviceMethod.adapt()方法,将OkHttpCall进行代理包装。
2.2.1、ServiceMethod serviceMethod = loadServiceMethod(method):
# Retrofit.class
//loadServiceMethod(method)负责加载 ServiceMethod
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
// 设置线程同步锁
synchronized (serviceMethodCache) {
// 创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例
// 若没缓存,则通过建造者模式创建 serviceMethod 对象
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
# ServiceMethod.class
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory;
final CallAdapter<?> callAdapter;
private final Converter<ResponseBody, T> responseConverter;
// Response内容转换器:负责把服务器返回的数据(JSON或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象;
private final HttpUrl baseUrl; // 网络请求地址
private final String relativeUrl; // 网络请求的相对地址
private final String httpMethod; // 网络请求的Http方法
private final Headers headers; // 网络请求的http请求头 键值对
private final MediaType contentType; // 网络请求的http报文body的类型
private final ParameterHandler<?>[] parameterHandlers;
// 方法参数处理器:负责解析每个方法里的参数,并在构造 HTTP 请求时设置参数;
ServiceMethod(Builder<R, T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
...
}
# ServiceMethod.Builder静态内部类
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 获取网络请求接口里的方法注解:PUT、GET ...
this.methodAnnotations = method.getAnnotations();
// 获取网络请求接口方法里的参数类型
this.parameterTypes = method.getGenericParameterTypes();
//获取网络请求接口方法里的参数注解:Body、Field ...
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
callAdapter = createCallAdapter();
//根据网络请求接口方法的返回值类型和注解类型,从Retrofit对象中获取对应的网络请求适配器
responseType = callAdapter.responseType();
//根据网络请求接口方法的返回值类型和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型
responseConverter = createResponseConverter();
// 根据网络请求接口方法的返回值类型和注解类型,从Retrofit对象中获取对应的数据转换器
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 解析网络请求接口中方法的注解,包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded
int parameterCount = parameterAnnotationsArray.length;
// 获取当前方法的参数数量
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
// 为方法中的每个参数创建一个ParameterHandler<?>对象并解析每个参数使用的注解类型:这里的注解包括:Body、PartMap、Part、FieldMap、Field、Header、QueryMap、Query、Path、Url
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
callAdapter.responseType():返回的是我们方法的实际类型,例如:Call,则返回User类型,然后对该类型进行判断。
createResponseConverter():负责把服务器返回的数据(JSON或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象。
- 接下来就是对注解进行解析了,主要是对方法上的注解进行解析,那么可以拿到httpMethod以及初步的url.
- 后面是对方法中参数中的注解进行解析,这一步会拿到很多的ParameterHandler对象,每一个参数创建一个ParameterHandler对象。
2.2.2、OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args):
- 这里生成Call的代理执行类:OkHttpCall类,将call放入okhttp的请求队列中。
- OkHttpCall类是OkHttp的包装类。
- 创建了OkHttpCall类型的Call对象还不能发送网络请求,需要创建Request对象才能发送网络请求。
2.2.3、serviceMethod.callAdapter.adapt(okHttpCall):
# ExecutorCallAdapterFactory.java
@Override
public Call<Object> adapt(Call<Object> 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;//把上面创建并配置好参数的OkhttpCall对象交给静态代理对象delegate.
}
...
}
2.3、发起网络请求:
- 步骤1:对网络请求接口的方法中的每个参数利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
- 通过serviceMethod.callAdapter.adapt(okHttpCall)去调用ExecutorCallAdapterFactory.adapt()方法.
- 进一步调用OkHttpCall类的一系列方法去创建Request请求对象。
- 步骤2:使用OkHttp的Request发送网络请求;
- 步骤3:对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个Response对象
- 步骤4:进行线程切换从而在主线程处理返回的数据结果
【异步跟同步请求不同之处在于:异步请求会将回调方法交给回调执行器在指定的线程中执行】
2.3.1、同步请求:
Response<JavaBean> response = call.execute();
2.3.2、异步请求:
call.enqueue(new Callback<JavaBean>() {
@Override
public void onResponse(Call<JavaBean> call, Response<JavaBean> response) {
if (response.isSuccessful()) {
response.body().show();
} else {
try {
System.out.println(response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
} ;
}
}
@Override
public void onFailure(Call<JavaBean> call, IOException e){
...
}
}