最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
当然我也为你们整理好了百度、阿里、腾讯、字节跳动等等互联网超级大厂的历年面试真题集锦。这也是我这些年来养成的习惯,一定要学会把好的东西,归纳整理,然后系统的消化吸收,这样才能极大的提高学习效率和成长进阶。碎片、零散化的东西,我觉得最没有价值的。就好比你给我一张扑克牌,我只会觉得它是一张废纸,但如果你给我一副扑克牌,它便有了它的价值。这和我们收集资料就要收集那些系统化的,是一个道理。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 初始化 Cache
mCache.initialize();
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
if (mQuit) {
return;
}
}
}
}
private void processRequest() throws InterruptedException {
final Request<?> request = mCacheQueue.take();
request.addMarker(“cache-queue-take”);
// 如果请求已经取消了,我们直接结束该请求
if (request.isCanceled()) {
request.finish(“cache-discard-canceled”);
return;
}
// 从 Cache 中取出包含请求缓存数据的 Entry
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker(“cache-miss”);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 如果缓存的请求过期了,就将其添加到网络请求队列中
if (entry.isExpired()) {
request.addMarker(“cache-hit-expired”);
request.setCacheEntry(entry);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 缓存的数据封装成 NetworkResponse
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
if (!entry.refreshNeeded()) {
// 如果缓存没有过期就直接进行分发
mDelivery.postResponse(request, response);
} else {
// 重置该请求的 Entry
request.setCacheEntry(entry);
response.intermediate = true;
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
} else {
mDelivery.postResponse(request, response);
}
}
}
代码相对比较长,我在关键的地方已经打上注释了,在这里总结一下,可以看到在初始化了 Cache 之后,有一个 while(true) 循环,说明缓存线程是始终执行的,接着会在缓存中取出响应结果,如果为 null 的话,就将其加入到网络请求队列中,如果不为空的话,再判断该缓存是否已过期,已经过期则同样把这条请求加入到网络请求队列中,否则直接使用缓存中的数据。最后将数据进行解析,并进行分发。
看完 CacheDispathcer 的 run() 方法,我们接着看 NetworkDispatcher 的 run() 方法
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
if (mQuit) {
return;
}
}
}
}
private void processRequest() throws InterruptedException {
Request<?> request = mQueue.take();
long startTimeMs = SystemClock.elapsedRealtime();
try {
request.addMarker(“network-queue-take”);
// 如果 Request 已经取消了,那就不执行网络请求
if (request.isCanceled()) {
request.finish(“network-discard-cancelled”);
request.notifyListenerResponseNotUsable();
return;
}
addTrafficStatsTag(request);
// 执行网络请求
NetworkResponse networkResponse = mNetwork.performRequest(request);
// 如果服务器返回 304,而且我们已经分发过该 Request 的结果,那就不用进行第二次分发了
//(这里补充一下,304 代表服务器上的结果跟上次访问的结果是一样的,也就是说数据没有变化)
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish(“not-modified”);
request.notifyListenerResponseNotUsable();
return;
}
// 在子线程解析返回的结果
Response<?> response = request.parseNetworkResponse(networkResponse);
// 如果需要的话,就将返回结果写入缓存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry); }
// 分发响应结果
request.markDelivered();
mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
} catch (VolleyError volleyError) {
request.notifyListenerResponseNotUsable();
} catch (Exception e) {
request.notifyListenerResponseNotUsable();
}
}
在 NetworkDispatcher 同样使用了 while(true),说明网络请求线程也是不断运行的。然后从网络队列里面取出 Request,再调用 Network 的 performRequest() 方法去发送网络请求。Network 其实是一个接口,这里具体的实现是 BasicNetwork,我们来看下它的 performRequest() 方法实现:
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
List
try {
Map<String, String> additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
// 该注意的地方:调用 Stack 的 executeRequest 进行网络请求
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null, true,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
}
List
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data,
true, SystemClock.elapsedRealtime() - requestStart, combinedHeaders);
}
// 有些返回结果是没有内容的,如:204,所以我们必须进行检查
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
responseContents =
inputStreamToBytes(inputStream, httpResponse.getContentLength());
} else {
responseContents = new byte[0];
}
return new NetworkResponse(statusCode, responseContents, false,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
} catch (Exception e) {
// …
}
}
}
这个方法里面,基本上都是网络请求方面处理的细节,我们这篇文章,主要是梳理整体的流程,对细节方面先不深入。需要注意的是在我标注的第一个地方,调用了 Stack 的 executeRequest() 方法,这里的 Stack 就是之前调用 Volley.newRequestQueue() 所创建的实例,前面也说过了这个对象的内部是使用了 HttpURLConnection 或 HttpClient(已弃用)来进行网络请求。网络请求结束后将返回的数据封装成一个 NetworkResponse 对象进行返回。
在 NetworkDispatcher 接收到了这个 NetworkResponse 对象之后,又会调用 Request 的 parseNetworkResponse() 方法来对结果进行解析,然后将数据写入到缓存,最后调用 ExecutorDelivery 的 postResponse() 方法来回调解析后的数据,如下所示:
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker(“post-response”);
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
在 mResponsePoster(一个 Executor 的实例对象) 的 execute() 方法中传入了一个 ResponseDeliveryRunnable 对象,execute() 方法默认是在主线程中执行的,这样就保证了 ResponseDeliveryRunnable 的 run() 方法也是在主线程当中运行的,我们看下 run() 方法里面的逻辑:
@SuppressWarnings(“unchecked”)
@Override
public void run() {
// 如果 Request 被取消了,调用 finish() 方法,结束该请求,不进行传递
if (mRequest.isCanceled()) {
mRequest.finish(“canceled-at-delivery”);
return;
}
// 根据响应的结果来进行不同的分发
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}
// 如果传入的 mRunnable 不为 null,则运行
if (mRunnable != null) {
mRunnable.run();
}
}
可以看到当 Response.isSuccess() 为 true 的话,调用 Resquest 的 deliverResponse() 方法,对结果进行回调,deliverResponse() 方法是每一个具体的 Request 子类都必须实现的抽象类,来看下我们最熟悉的 StringRequest 中的 deliverResponse() 方法
@Override
protected void deliverResponse(String response) {
Response.Listener listener;
synchronized (mLock) {
listener = mListener;
}
if (listener != null) {
listener.onResponse(response);
}
}
看到这里应该就很明白了,在 deliverResponse() 方法中,调用 listener.onResponse() 方法进行回调,这个 listener 正是我们构建 StringRequest 时传入的 Listener,也就是说将返回的结果回调到我们在外部调用的地方。
StringRequest stringRequest = new StringRequest(url
, new Response.Listener() {
@Override
public void onResponse(String s) {
// TODO:
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO:
}
});
题外话
不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊
这里我为大家准备了一些我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
欢迎评论区讨论。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
TODO:
}
});
题外话
不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备,当然除了这个还需要在平时把自己的基础打扎实,这样不论面试官怎么样一个知识点里往死里凿,你也能应付如流啊
这里我为大家准备了一些我工作以来以及参与过的大大小小的面试收集总结出来的一套进阶学习的视频及面试专题资料包,主要还是希望大家在如今大环境不好的情况下面试能够顺利一点,希望可以帮助到大家~
[外链图片转存中…(img-X8HFS7Oi-1715729797091)]
欢迎评论区讨论。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!