尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
展示学习笔记
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
//获取我们的原始的类型,跟我们判断选择不同的CallAdapter有关系
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
CallAdapter就是网络请求适配器,它的其中一个实现类就是RxJavaCallAdapter
如果要实现RxjavaCallAdapterFactory的配置
1、首先要实现CallAdapter.Factory抽象类,用来提供具体的适配逻辑
2、然后通过addCallAdapterFactory方法添加到Retrofit中(注册CallAdapter)
3、调用Factory.get方法来获取我们的CallAdapter
4、调用CallAdapter中的adapter方法,将我们Call请求转换成每一个平台所适用的类型。
retrofit请求网络基本流程:
获取到Call对象去执行请求,而retrofit调用这个call请求其实最终调用的是okhttp的call请求,只不过是封装了。
然后去服务端获取数据,获取到数据后调用converter(数据转换器)转换数据,
> 六、网络请求接口实例(ServiceMethod)解析
Retrofit请求流程:
Retrofit retrofit = new Retrofit.Builder().baseUrl("")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
Apis apis = retrofit.create(Apis.class);
Call<HttpResponse<List<Coin>>> call = apis.getCoinList(null);
call.enqueue(new retrofit2.Callback<HttpResponse<List<Coin>>>() {
@Override
public void onResponse(retrofit2.Call<HttpResponse<List<Coin>>> call, retrofit2.Response<HttpResponse<List<Coin>>> response) {
}
@Override
public void onFailure(retrofit2.Call<HttpResponse<List<Coin>>> call, Throwable t) {
}
});
接口定义好以后,是通过动态代理的方式把接口转换为实际请求,ServiceMethod对应的就是一个一个的接口方法。
create方法中:
public T create(final Class service) {
Utils.validateServiceInterface(service);
//1、会先判断是否是一个有效的method,判断是否有效会先执行loadServiceMethod方法
if (validateEagerly) {
eagerlyValidateMethods(service);
}
//2、然后通过动态代理invoke方法中解析方法的注解(这个方法里面同样要执行loadServiceMethod方法)。
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 {
//invoke方法中3行最经典的代码(也是retrofit中最核心的3行代码):
//retrofit的核心是这3行代码,3行代码的核心是ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
> **第一行核心代码解析(ServiceMethod<Object, Object> serviceMethod =
> (ServiceMethod<Object, Object>) loadServiceMethod(method)😉**
//获得ServiceMethod,先从ServiceMethodCache中获取,如果缓存中没有,再重新构建,然后再把新获取的缓存到ServiceMethodCache中
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//如果没有缓存就重新创建一个ServiceMethod实例并缓存
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
**下面具体解析:result = new ServiceMethod.Builder<>(this, method).build();**
如何通过动态代理把我们定义的网络接口转换为ServiceMethod(实际请求对象)?
下面看看ServiceMethod类,有几个重要的变量,这几个变量包含了我们所有的网络请求的基本信息,它的初始化也是builder模式:
final class ServiceMethod<R, T> {
//OkHttp中的Call
final okhttp3.Call.Factory callFactory;
//网络请求适配器比如(RxjavaCallAdapter)
final CallAdapter<R, T> callAdapter;
private final HttpUrl baseUrl;
//数据转换器(GsonConverterAdapter)
private final Converter<ResponseBody, R> responseConverter;
//get post delete 等
private final String httpMethod;
//相对地址(和baseurl拼接在一起)
private final String relativeUrl;
//请求头
private final Headers headers;
//body
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
//最核心的,方法参数的处理器(方法和方法上面的注解都是它解析的)
private final ParameterHandler<?>[] parameterHandlers;
一、下面是builder模式内部类,注意3,4,5
Builder(Retrofit retrofit, Method method) {
//1、retrofit对象
this.retrofit = retrofit;
//2、请求方法名
this.method = method;
//3、网络请求接口里面的注解
this.methodAnnotations = method.getAnnotations();
//4、获取请求接口中参数的类型
this.parameterTypes = method.getGenericParameterTypes();
//5、获取注解里面的内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
}
二、build()方法
根据responseType和方法中的注解来解析整个需要的内容
public ServiceMethod build() {
//1、通过网络请求方法的返回值和注解类型,从retrofit对象中获取请求适配器。
callAdapter = createCallAdapter();
//2、根据网络请求接口方法的返回值和注解类型,从retrofit对象中获取这个请求适配器返回的数据类型
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?");
}
//3、创建数据转换器
responseConverter = createResponseConverter();
//4、遍历注解,解析注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//5、遍历参数,解析参数
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
总结build()方法:
根据返回值类型和方法中的注解来从网络请求适配器工厂和数据转换器工厂分别获取到(request)请求适配器(callAdapter)和(response) 数据返回转换器(converter);
然后会根据参数注解来获取到参数;最后调用parseParameter解析结果中的参数。
> 其中里面的方法:
private CallAdapter<T, R> createCallAdapter() {
//网络接口方法返回的类型
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
//获取网络请求接口里面的注解
Annotation[] annotations = method.getAnnotations();
try {
//returnType:网络请求方法的返回值 ;annotations:注解类型
return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
调用:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
调用:
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, "returnType == null");
checkNotNull(annotations, "annotations == null");
//遍历callAdapter的工厂集合寻找合适的工厂,然后通过get方法来获取CallAdapter,最后赋值给ServiceMethod的callAdapter
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
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);
}
}
调用:
public Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
调用:
public Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
checkNotNull(type, "type == null");
checkNotNull(annotations, "annotations == null");
//遍历converter的工厂集合寻找合适的工厂,然后通过get方法来获取converter,最后赋值给ServiceMethod的converter
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
}
> **第二行核心代码解析OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);**
OkHttpCall实际调用的是okhttp3.Call rawCall,根据serviceMethod和参数创建Call对象,它就是封装了OkHttp中的Call对象
> **第三行核心代码解析 return serviceMethod.callAdapter.adapt(okHttpCall);**
调用CallAdapter中的adapter方法,将我们Call请求转换成每一个平台所适用的类型。
到此,我们就把creat方法解析完毕了。
那么下面就看看create之后的请求了
Apis apis = retrofit.create(Apis.class);
retrofit2.Call<HttpResponse<List<Coin>>> call = apis.getCoinList(null);
call.enqueue(new retrofit2.Callback<HttpResponse<List<Coin>>>() {
@Override
public void onResponse(retrofit2.Call<HttpResponse<List<Coin>>> call, retrofit2.Response<HttpResponse<List<Coin>>> response) {
}
@Override
public void onFailure(retrofit2.Call<HttpResponse<List<Coin>>> call, Throwable t) {
}
});
同步请求和重要参数
retrofit请求:
retrofit帮我们封装了所有的请求,最终还是交给OkHttp去请求
同步:OkHttpCall.execute()
异步:OkHttpCall.enqueue()
> retrofit中具体请求流程:
1、网络接口中的方法和参数利用ParameterHandle来进行解析
2、根据ServiceMethod对象创建一个OkHttp的request对象,有了这个对象才能进行实际的网络请求
(ServiceMethod这个对象很重要,所有需要缓存,它得到后就缓存在ServiceMethodCache中)
3、从ServiceMethod获取到request对象,通过OkHttpCall的底层:OkHttp库发送网络请求
4、通过converter解析数据
一句话总结:
对网络请求接口方法中的每个参数利用ParameterHandle来进行解析,第二步根据我们创建好的ServiceMethod对象创建Request对象,把Request对象交给OkHttp库来进行实际的网络请求发送,发送完后利用数据转换器converter将网络数据转为Java对象。
使用retrofit只需要将焦点放在接口的创建上,通过接口来配置请求即可,它内部的原理就是通过动态代理将接口中的方法转换为ServiceMethod对象,然后通过ServiceMethod对象获取到请求信息,最终网络底层的请求还是交给OkHttp请求的。
在retrofit中:final class OkHttpCall implements Call {},所以call.enqueue或call.execute最终调用的是OkHttpCall中的方法;OkHttpCall中实际使用了:okhttp3.Call
call.enqueue或call.execute最终都会调用createRawCall和parseResponse;
createRawCall得到okhttp3.Call对象,parseResponse解析数据返回
下面具体代码:
private okhttp3.Call createRawCall() throws IOException {
//调用ParameterHandle解析参数后创建Request对象
Request request = serviceMethod.toRequest(args);
//创建Call对象
最后
针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
khttp3.Call createRawCall() throws IOException {
//调用ParameterHandle解析参数后创建Request对象
Request request = serviceMethod.toRequest(args);
//创建Call对象
最后
针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。
(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。
[外链图片转存中…(img-ClRKPPFv-1715889173621)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!