AccessApi NetService = retrofit.create(NetService.class);
<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象 -->
Call call = NetService.getCall();
复制代码
步骤3讲解:AccessApi NetService = retrofit.create(NetService.class);
public T create(final Class service) {
if (validateEagerly) {
// 判断是否需要提前验证
eagerlyValidateMethods(service);
// 具体方法作用:
// 1. 给接口中每个方法的注解进行解析并得到一个ServiceMethod对象
// 2. 以Method为键将该对象存入LinkedHashMap集合中
// 特别注意:如果不是提前验证则进行动态解析对应方法(下面会详细说明),得到一个ServiceMethod对象,最后存入到LinkedHashMap集合中,类似延迟加载(默认)
}
// 创建了网络请求接口的动态代理对象,即通过动态代理创建网络请求接口的实例 (并最终返回)
// 该动态代理是为了拿到网络请求接口实例上所有注解
return (T) Proxy.newProxyInstance(
service.getClassLoader(), // 动态生成接口的实现类
new Class<?>[] { service }, // 动态创建实例
new InvocationHandler() { // 将代理类的实现交给 InvocationHandler类作为具体的实现(下面会解释)
private final Platform platform = Platform.get();
// 在 InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),还可以进行一些有用的操作
// 如统计执行时间、进行初始化和清理、对接口调用进行检查等。
@Override
public Object invoke(Object proxy, Method method, Object… args)
throws Throwable {
// 下面会详细介绍 invoke()的实现
// 即下面三行代码
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
// 特别注意
// return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
// 可以解读为:getProxyClass(loader, interfaces) .getConstructor(InvocationHandler.class).newInstance(invocationHandler);
// 即通过动态生成的代理类,调用interfaces接口的方法实际上是通过调用InvocationHandler对象的invoke()来完成指定的功能
// 先记住结论,在讲解步骤4的时候会再次详细说明
<-- 关注点1:eagerlyValidateMethods() -->
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method)) { loadServiceMethod(method); }
// 将传入的ServiceMethod对象加入LinkedHashMap<Method, ServiceMethod>集合
// 使用LinkedHashMap集合的好处:lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,提供了一种Lru算法的实现
}
}
创建网络接口实例用了外观模式 & 代理模式:
1. 外观模式
-
外观模式:定义一个统一接口,外部与通过该统一的接口对子系统里的其他接口进行访问。具体请看:外观模式(Facade Pattern) - 最易懂的设计模式解析
-
Retrofit对象的外观(门店) =
retrofit.create()
-
通过这一外观方法就可以在内部调用各个方法创建网络请求接口的实例和配置网络请求参数
2. 代理模式
- 代理模式:通过访问代理对象的方式来间接访问目标对象
return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
通过代理模式中的动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给InvocationHandler类
作为具体的实现,并最终返回一个动态代理对象。
使用动态代理的好处:
- 当
NetService
对象调用getCall()
接口中方法时会进行拦截,调用都会集中转发到 InvocationHandler#invoke (),可集中进行处理 - 获得网络请求接口实例上的所有注解
- 更方便封装ServiceMethod
下面看源码分析
下面将详细分析InvocationHandler类 # invoke()
里的具体实现
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object… args)
throws Throwable {
// 将详细介绍下面代码
// 关注点1
// 作用:读取网络请求接口里的方法,并根据前面配置好的属性配置serviceMethod对象
ServiceMethod serviceMethod = loadServiceMethod(method);
// 关注点2
// 作用:根据配置好的serviceMethod对象创建okHttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 关注点3
// 作用:调用OkHttp,并根据okHttpCall返回rejava的Observe对象或者返回Call
return serviceMethod.callAdapter.adapt(okHttpCall);
}
复制代码
下面将详细介绍3个关注点的代码。
关注点1: ServiceMethod serviceMethod = loadServiceMethod(method);
<-- loadServiceMethod(method)方法讲解 -->
// 一个 ServiceMethod 对象对应于网络请求接口里的一个方法
// loadServiceMethod(method)负责加载 ServiceMethod:
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
// 设置线程同步锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
// ServiceMethod类对象采用了单例模式进行创建
// 即创建ServiceMethod对象前,先看serviceMethodCache有没有缓存之前创建过的网络请求实例
// 若没缓存,则通过建造者模式创建 serviceMethod 对象
if (result == null) {
// 下面会详细介绍ServiceMethod生成实例的过程
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
// 这里就是上面说的创建实例的缓存机制:采用单例模式从而实现一个 ServiceMethod 对象对应于网络请求接口里的一个方法
// 注:由于每次获取接口实例都是传入 class 对象
// 而 class 对象在进程内单例的,所以获取到它的同一个方法 Method 实例也是单例的,所以这里的缓存是有效的。
下面,我将分3个步骤详细分析serviceMethod
实例的创建过程:
步骤1:ServiceMethod类
构造函数
<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory; // 网络请求工厂
final CallAdapter<?> callAdapter;
// 网络请求适配器工厂
// 具体创建是在new ServiceMethod.Builder(this, method).build()最后的build()中
// 下面会详细说明
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;
// 方法参数处理器
// 作用:负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;
// 下面会详细说明
// 说明:从上面的成员变量可以看出,ServiceMethod对象包含了访问网络的所有基本信息
<-- ServiceMethod 类的构造函数 -->
// 作用:传入各种网络请求参数
ServiceMethod(Builder builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.responseConverter = builder.responseConverter;
this.baseUrl = builder.retrofit.baseUrl();
this.relativeUrl = builder.relativeUrl;
this.httpMethod = builder.httpMethod;
this.headers = builder.headers;
this.contentType = builder.contentType; .
this.hasBody = builder.hasBody; y
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
步骤2:ServiceMethod的Builder()
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
// 获取网络请求接口方法里的注释
this.methodAnnotations = method.getAnnotations();
// 获取网络请求接口方法里的参数类型
this.parameterTypes = method.getGenericParameterTypes();
//获取网络请求接口方法里的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
步骤3:ServiceMethod的build()
// 作用:控制ServiceMethod对象的生成流程
public ServiceMethod build() {
callAdapter = createCallAdapter();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器 -->关注点1
responseType = callAdapter.responseType();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取该网络适配器返回的数据类型
responseConverter = createResponseConverter();
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的数据转换器 -->关注点3
// 构造 HTTP 请求时,我们传递的参数都是String
// Retrofit 类提供 converter把传递的参数都转化为 String
// 其余类型的参数都利用 Converter.Factory 的stringConverter 进行转换
// @Body 和 @Part 类型的参数利用Converter.Factory 提供的 requestBodyConverter 进行转换
// 这三种 converter 都是通过“询问”工厂列表进行提供,而工厂列表我们可以在构造 Retrofit 对象时进行添加。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 解析网络请求接口中方法的注解
// 主要是解析获取Http请求的方法
// 注解包括:DELETE、GET、POST、HEAD、PATCH、PUT、OPTIONS、HTTP、retrofit2.http.Headers、Multipart、FormUrlEncoded
// 处理主要是调用方法 parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) ServiceMethod中的httpMethod、hasBody、relativeUrl、relativeUrlParamNames域进行赋值
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);
<-- 总结 -->
// 1. 根据返回值类型和方法标注从Retrofit对象的的网络请求适配器工厂集合和内容转换器工厂集合中分别获取到该方法对应的网络请求适配器和Response内容转换器;
// 2. 根据方法的标注对ServiceMethod的域进行赋值
// 3. 最后为每个方法的参数的标注进行解析,获得一个ParameterHandler<?>对象
// 该对象保存有一个Request内容转换器——根据参数的类型从Retrofit的内容转换器工厂集合中获取一个Request内容转换器或者一个String内容转换器。
}
<-- 关注点1:createCallAdapter() -->
private CallAdapter<?> createCallAdapter() {
// 获取网络请求接口里方法的返回值类型
Type returnType = method.getGenericReturnType();
// 获取网络请求接口接口里的注解
// 此处使用的是@Get
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.callAdapter(returnType, annotations);
// 根据网络请求接口方法的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
// 下面会详细说明retrofit.callAdapter() – >关注点2
}
…
<-- 关注点2:retrofit.callAdapter() -->
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
// 创建 CallAdapter 如下
// 遍历 CallAdapter.Factory 集合寻找合适的工厂(该工厂集合在第一步构造 Retrofit 对象时进行添加(第一步时已经说明))
// 如果最终没有工厂提供需要的 CallAdapter,将抛出异常
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
<-- 关注点3:createResponseConverter() -->
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
// responseConverter 还是由 Retrofit 类提供 -->关注点4
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) {
throw methodError(e, “Unable to create converter for %s”, responseType);
}
}
<-- 关注点4:responseBodyConverter() -->
public Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
// 获取Converter 过程:(和获取 callAdapter 基本一致)
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
// 遍历 Converter.Factory 集合并寻找合适的工厂(该工厂集合在构造 Retrofit 对象时进行添加(第一步时已经说明))
// 由于构造Retroifit采用的是Gson解析方式,所以取出的是GsonResponseBodyConverter
// Retrofit - Converters 还提供了 JSON,XML,ProtoBuf 等类型数据的转换功能。
// 继续看responseBodyConverter() -->关注点5
}
<-- 关注点5:responseBodyConverter() -->
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
// 根据目标类型,利用 Gson#getAdapter 获取相应的 adapter
return new GsonResponseBodyConverter<>(gson, adapter);
}
// 做数据转换时调用 Gson 的 API 即可。
final class GsonResponseBodyConverter implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
- 当选择了RxjavaCallAdapterFactory后,Rxjava通过策略模式选择对应的adapter
- 具体过程是:根据网络接口方法的返回值类型来选择具体要用哪种CallAdapterFactory,然后创建具体的CallAdapter实例
采用工厂模式使得各功能模块高度解耦
- 上面提到了两种工厂:CallAdapter.Factory & Converter.Factory分别负责提供不同的功能模块
- 工厂负责如何提供、提供何种功能模块
- Retrofit 只负责提供选择何种工厂的决策信息(如网络接口方法的参数、返回值类型、注解等)
这正是所谓的高内聚低耦合,工厂模式get。
简单工厂模式(SimpleFactoryPattern)- 最易懂的设计模式解析
工厂方法模式(Factory Method)- 最易懂的设计模式解析
抽象工厂模式(Abstract Factory)- 最易懂的设计模式解析
终于配置完网络请求参数(即配置好ServiceMethod
对象)。接下来将讲解第二行代码:okHttpCall对象
的创建
第二行:OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
根据第一步配置好的ServiceMethod
对象和输入的请求参数创建okHttpCall
对象
<–OkHttpCall类 -->
public class OkHttpCall {
private final ServiceMethod serviceMethod; // 含有所有网络请求参数信息的对象
private final Object[] args; // 网络请求接口的参数
private okhttp3.Call rawCall; //实际进行网络访问的类
private Throwable creationFailure; //几个状态标志位
private boolean executed;
private volatile boolean canceled;
<–OkHttpCall构造函数 -->
public OkHttpCall(ServiceMethod serviceMethod, Object[] args) {
// 传入了配置好的ServiceMethod对象和输入的请求参数
this.serviceMethod = serviceMethod;
this.args = args;
}
第三行:return serviceMethod.callAdapter.adapt(okHttpCall);
将第二步创建的OkHttpCall
对象传给第一步创建的serviceMethod
对象中对应的网络请求适配器工厂的adapt()
<-- adapt()详解–>
public Call adapt(Call call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.delegate = delegate;
// 把上面创建并配置好参数的OkhttpCall对象交给静态代理delegate
// 静态代理和动态代理都属于代理模式
// 静态代理作用:代理执行被代理者的方法,且可在要执行的方法前后加入自己的动作,进行对系统功能的拓展
this.callbackExecutor = callbackExecutor;
// 传入上面定义的回调方法执行器
// 用于进行线程切换
}
- 采用了装饰模式:ExecutorCallbackCall = 装饰者,而里面真正去执行网络请求的还是OkHttpCall
- 使用装饰模式的原因:希望在OkHttpCall发送请求时做一些额外操作。这里的额外操作是线程转换,即将子线程切换到主线程
步骤4讲解:Call<JavaBean> call = NetService.getCall();
NetService
对象实际上是动态代理对象Proxy.newProxyInstance()
(步骤3中已说明),并不是真正的网络请求接口创建的对象- 当
NetService
对象调用getCall()
时会被动态代理对象Proxy.newProxyInstance()
拦截,然后调用自身的InvocationHandler # invoke()
invoke(Object proxy, Method method, Object... args)
会传入3个参数:Object proxy:
(代理对象)、Method method
(调用的getCall()
)Object... args
(方法的参数,即getCall(*)
中的*)- 接下来利用Java反射获取到
getCall()
的注解信息,配合args参数创建ServiceMethod对象
。
最终创建并返回一个OkHttpCall
类型的Call对象
总结
Retrofit采用了外观模式统一调用创建网络请求接口实例和网络请求参数配置的方法,具体细节是:
- 动态创建网络请求接口的实例**(代理模式 - 动态代理)**
- 创建
serviceMethod
对象**(建造者模式 & 单例模式(缓存机制))** - 对
serviceMethod
对象进行网络请求参数配置:通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络请求的url地址、网络请求执行器、网络请求适配器 & 数据转换器。(策略模式) - 对
serviceMethod
对象加入线程切换的操作,便于接收数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理**(装饰模式)** - 最终创建并返回一个
OkHttpCall
类型的网络请求对象
3. 执行网络请求
Retrofit
默认使用OkHttp
,即OkHttpCall类
(实现了retrofit2.Call<T>
接口)
OkHttpCall
提供了两种网络请求方式:
- 同步请求:
OkHttpCall.execute()
- 异步请求:
OkHttpCall.enqueue()
下面将详细介绍这两种网络请求方式。
3.1 同步请求OkHttpCall.execute()
3.1.1 发送请求过程
- 步骤1: 对网络请求接口的方法中的每个参数利用对应
ParameterHandler
进行解析,再根据ServiceMethod
对象创建一个OkHttp
的Request
对象 - 步骤2: 使用
OkHttp
的Request
发送网络请求; - 步骤3: 对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个
Response<T>
对象
3.1.2 具体使用
Response response = call.execute();
上面简单的一行代码,其实包含了整个发送网络同步请求的三个步骤。
3.1.3 源码分析
@Override
public Response execute() throws IOException {
okhttp3.Call call;
// 设置同步锁
synchronized (this) {
call = rawCall;
if (call == null) {
try {
call = rawCall = createRawCall();
// 步骤1:创建一个OkHttp的Request对象请求 -->关注1
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
return parseResponse(call.execute());
// 步骤2:调用OkHttpCall的execute()发送网络请求(同步)
// 步骤3:解析网络请求返回的数据parseResponse() -->关注2
}
<-- 关注1:createRawCall() -->
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
// 从ServiceMethod的toRequest()返回一个Request对象
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
// 根据serviceMethod和request对象创建 一个okhttp3.Request
if (call == null) {
throw new NullPointerException(“Call.Factory returned null.”);
}
return call;
}
<-- 关注2:parseResponse()–>
Response 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) {
}
if (code == 204 || code == 205) {
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
T body = serviceMethod.toResponse(catchingBody);
// 等Http请求返回后 & 通过状态码检查后,将response body传入ServiceMethod中,ServiceMethod通过调用Converter接口(之前设置的GsonConverterFactory)将response body转成一个Java对象,即解析返回的数据
// 生成Response类
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
… // 异常处理
}
}
特别注意:
ServiceMethod
几乎保存了一个网络请求所需要的数据- 发送网络请求时,
OkHttpCall
需要从ServiceMethod
中获得一个Request对象 - 解析数据时,还需要通过
ServiceMethod
使用Converter
(数据转换器)转换成Java对象进行数据解析
- 关于状态码检查时的状态码说明:
以上便是整个以同步的方式发送网络请求的过程。
3.2 异步请求OkHttpCall.enqueue()
3.2.1 发送请求过程
- 步骤1: 对网络请求接口的方法中的每个参数利用对应
ParameterHandler
进行解析,再根据ServiceMethod
对象创建一个OkHttp
的Request
对象 - 步骤2: 使用
OkHttp
的Request
发送网络请求; - 步骤3: 对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个
Response<T>
对象 - 步骤4: 进行线程切换从而在主线程处理返回的数据结果
异步请求的过程跟同步请求类似,唯一不同之处在于:异步请求会将回调方法交给回调执行器在指定的线程中执行。
3.2.2 具体使用
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
System.out.println(response.isSuccessful());
if (response.isSuccessful()) {
response.body().show();
}
else {
try {
System.out.println(response.errorBody().string());
} catch (IOException e) {
e.printStackTrace();
} ;
}
}
- 从上面分析有:
call
是一个静态代理 - 使用静态代理的作用是:在okhttpCall发送网络请求的前后进行额外操作
3.2.3 源码分析
<-- call.enqueue()解析 -->
@Override
public void enqueue(final Callback callback) {
delegate.enqueue(new Callback() {
// 使用静态代理 delegate进行异步请求 ->>分析1
// 等下记得回来
@Override
public void onResponse(Call call, final Response response) {
// 步骤4:线程切换,从而在主线程显示结果
callbackExecutor.execute(new Runnable() {
// 最后Okhttp的异步请求结果返回到callbackExecutor
// callbackExecutor.execute()通过Handler异步回调将结果传回到主线程进行处理(如显示在Activity等等),即进行了线程切换
// 具体是如何做线程切换 ->>分析2
@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 call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
<-- 分析1:delegate.enqueue()解析 -->
@Override
public void enqueue(final Callback callback) {
okhttp3.Call call;
Throwable failure;
// 步骤1:创建OkHttp的Request对象,再封装成OkHttp.call
// delegate代理在网络请求前的动作:创建OkHttp的Request对象,再封装成OkHttp.call
synchronized (this) {
if (executed) throw new IllegalStateException(“Already executed.”);
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
// 创建OkHttp的Request对象,再封装成OkHttp.call
// 方法同发送同步请求,此处不作过多描述
} catch (Throwable t) {
failure = creationFailure = t;
}
}
// 步骤2:发送网络请求
// delegate是OkHttpcall的静态代理
// delegate静态代理最终还是调用Okhttp.enqueue进行网络请求
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
尾声
面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Android核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、热修复设计、插件化框架解读、组件化框架设计、图片加载框架、网络、设计模式、设计思想与代码质量优化、程序性能优化、开发效率优化、设计模式、负载均衡、算法、数据结构、高级UI晋升、Framework内核解析、Android组件内核等。
不仅有学习文档,视频+笔记提高学习效率,还能稳固你的知识,形成良好的系统的知识体系。这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《2017-2020字节跳动Android面试历年真题解析》
如果需要PDF版本可以自行领取!
-
点击这里直达下载领取链接
[外链图片转存中…(img-JzL95nWT-1646392199482)]
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
[外链图片转存中…(img-PO4X2jBx-1646392199483)]
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
[外链图片转存中…(img-JZM33Yd8-1646392199483)]
《2017-2020字节跳动Android面试历年真题解析》
[外链图片转存中…(img-XU3GmKJl-1646392199483)]
如果需要PDF版本可以自行领取!
-
点击这里直达下载领取链接