面试宝典
面试必问知识点、BATJ历年历年面试真题+解析
学习经验总结
(一)调整好心态
心态是一个人能否成功的关键,如果不调整好自己的心态,是很难静下心来学习的,尤其是现在这么浮躁的社会,大部分的程序员的现状就是三点一线,感觉很累,一些大龄的程序员更多的会感到焦虑,而且随着年龄的增长,这种焦虑感会越来越强烈,那么唯一的解决办法就是调整好自己的心态,要做到自信、年轻、勤奋。这样的调整,一方面对自己学习有帮助,另一方面让自己应对面试更从容,更顺利。
(二)时间挤一挤,制定好计划
一旦下定决心要提升自己,那么再忙的情况下也要每天挤一挤时间,切记不可“两天打渔三天晒网”。另外,制定好学习计划也是很有必要的,有逻辑有条理的复习,先查漏补缺,然后再系统复习,这样才能够做到事半功倍,效果才会立竿见影。
(三)不断学习技术知识,更新自己的知识储备
对于一名程序员来说,技术知识方面是非常重要的,可以说是重中之重。**要面试大厂,自己的知识储备一定要非常丰富,若缺胳膊少腿,别说在实际工作当中,光是面试这一关就过不了。**对于技术方面,首先基础知识一定要扎实,包括自己方向的语言基础、计算机基础、算法以及编程等等。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
在示例中,我们定义了网络接口Githubservice,然后使用创建的Retrofit对象的create方法来实现该接口,网络接口的实现为Retrofit最重要的逻辑,而网络接口的实现就是使用Java的动态代理实现的。create方法的调用和实现如下:
GitHubService githubService = retrofit.create(GitHubService.class);
public T create(final Class 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, Object… args)
throws Throwable {
…
//创建ServiceMthod对象,完成接口方法的解析和封装
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
Retrofit的create方法的主要逻辑就是返回一个GithubService接口的代理对象。注意这里是代理对象,并不是通过implement关键字实现GithubService接口的实现类,当我们调用代理对象的接口方法时,如调用listRepos方法时:
Call<Lsit> octocat = githubSerivce.listRepos(“octocat”);
就会触发InvocationHandler的invoke方法的调用来完成listRepos接口的实现:返回一个Call< T>对象。
在invoke方法中,调用loadServiceMethod加载一个ServiceMethod对象,如果已经加载过了,则会从缓存中获取,如果没有缓存,则会创建一个新的ServiceMethod对象,在创建过程中完成了对网络接口方法的解析,进而封装成一个ServiceMethod对象。ServiceMethod对象中的成员变量如下:
final class ServiceMethod<R,T>{
final okhttp3.Call.Factory callFactory;
final CallAdapter<R,T> callAdapter;
private final HttpUrl baseUrl;
private final Converter<RespinseBody,R> respinserConverter;
private final String httpMethod; //请求方法:POST GET等
private final String relativeUrl;
private final Headers headers; //请求头
private final MediaType contentType;
…
}
这些成员变量大部分都是通过解析网络接口方法的注解完成初始化的。在获取到ServiceMethod对象后,使用它完成OkHttpCall< Object>对象的创建。最后通过代码:
return serviceMethod.callAdapter.adapt(okHttpCall);
返回一个对象。这个对象在当前示例下返回的是一个 ExecutorCallbackCall对象,它的创建过程还是比较复杂的,首先serviceMethod中的callAdapter对象是由createCallAdapter创建,而 createCallAdater内部是使用Retrofit对象来获取一个CallAdapter对象,createCallAdapter的调用和实现如下:
public ServiceMethod build() {
callAdapter = createCallAdapter();
}
private CallAdapter<?> createCallAdapter() {
…
try {
return 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);
}
}
…
callAdapter方法会遍历CallAdapter.Factory集合adapterFactories,根据网络接口方法的返回值来匹配CallAdapter对象,进而返回对应的CallAdapter。Retrofit的callAdapter方法的实现如下:
//Retrofit.java
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
checkNotNull(returnType, “returnType == null”);
checkNotNull(annotations, “annotations == null”);
int start = adapterFactories.indexOf(skipPast) + 1;
//遍历CallAdapter.Factory集合
for (int i = start, count = adapterFactories.size(); i < count; i++) {
//根据网络接口的返回类型匹配相对应的CallAdapter.Factroy,进而获取CallAdapter对象
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
…
throw new IllegalArgumentException(builder.toString());
}
之前在创建Retrofit对象的时候,会默认添加一个ExecutorCallAdapterFactroy对象到CallAdapter.Factory的集合中。
所以在遍历CallAdapter.Factroy集合遍历到ExecutorCallAdapterFactory对象时,就会调用该对象的get方法获取一个CallAdapter对象:
//ExecutorCallAdapterFactory.java
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType);
// 如果匹配的类型不为Call则返回null
if (rawType != Call.class) {
return null
}
final Type responseType = Utils.getCallResponseType(returnType);
//返回一个CallAdapter对象
return new CallAdapter<Object,Call<?>>{
@Override
public Type responseType(){
return responseType
}
@Override
public Call adapter(Call call){
return new ExecutorCallback<>(callbackExecutor,call);
}
}
}
在get方法中会根据网络接口的返回类型进行匹配,如果返回类型不为Call,则返回null,如果为Call类型,比如网络接口方法listRepos的返回类型为Call,那么就会通过判断来返回一个CallAdapter对象。再回到之前的代码:
serviceMethod.callAdapter.adapter(okHttpCall);
所以serviceMethod.callAdapter实际上是获取的是CallAdapter对象,CallAdapter对象的adapter方法会返回一个ExecutorCallbackCall对象。
所以,如果网络接口的返回类型为Call类型,那么在InvocationHandler的invoke方法中返回对象的类型为ExecutorCallbackCall。
通过网络接口的的实现可知,调用接口方法如下:
Call<List> octocat = getHubService.listRepos(“octocat”);
返回的Call对象实际上是ExecutorCallbackCall对象,所以接下来我们使用Call对象发送网络请求,如异步网络请求:
octocat.enqueue(mCallback);
实际上执行的是ExecutorCallbackCall中的enqueue方法,enqueue方法的实现如下:
@Override
public void enqueue(final Callback callback) {
…
call.enqueue(new okhttp3.Callback() {
//内部使用okhttp完成异步请求
@Override
//网络成功的回调
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
…
});
在enqueue方法内部,最终使用OkHttp执行网络请求,网络响应或失败都会通过MainThreadExecutor分发到主线程。
- 从Retrofit的
build
方法 建造出一个 Retrofit对象,过程中有两个重要的工厂集合:
(1)adapterFactories
集合,是CallAdapter的工厂实现类,里面装着网络回调执行器callbackExecutor(就是绑定主线程的Handler)
(2)converterFactories
集合,Converter的工厂实现类,里面装着网络响应转化器,比如说Gson
- 网络接口的实现为Retrofit的最终要的逻辑,也就是其
create
方法
通过动态代理将网络接口转化成一个ServiceMethod
对象,这个ServiceMethod中封装了网络请求的所有信息,然后通过 OkHttpCall<>(ServiceMehtod,args)
来封装成一个OkhttpCall对象,最后用这个OkHttpCall通过callAdapter
方法 遍历一开始的adapterFactories集合,通过get
方法最终来返回与网络接口匹配的CallAdapter对象。
- 通过create最终创造的CallAdapter对象可以通过调用其接口方法其实现一个同步/异步请求。
在异步请求中,enqueue
实际上就是调用CallAdapter的enqueue方法 通过OkHttp
实现网络请求,执行的结果通过MainThreadExecutor对象回调到主线程中。
有人就会问了,为什么Retrofit的网络请求是基于Okhttp,我们要去用Retrofit,而不是直接去用OkHttp呢?
我们先来看看OkHttp的特点:
-
支持SPDY,因此可以同一IP多个连接共享同一个socket(SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强)
-
在Http/2不可用时, 连接池可极大减少延时;
-
支持Gzip压缩响应体,降低传输内容的大小;
-
支持Http缓存,避免重复请求;
-
服务器
最后
这里我希望可以帮助到大家提升进阶。
内容包含:Android学习PDF+架构视频+面试文档+源码笔记,高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。
喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
** 这几块的内容。非常适合近期有面试和想在技术道路上继续精进的朋友。
喜欢本文的话,不妨给我点个小赞、评论区留言或者转发支持一下呗~
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!