尾声
以薪资待遇为基础,以发展为最终目标,要在高薪资的地方,谋求最好的发展!
下面是有几位Android行业大佬对应上方技术点整理的一些进阶资料。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
OkHttpClient client = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url(“http://www.baidu.com”).build();
Call call = client.newCall(request);
try {
Response response = call.execute();
String s = new String().concat(response.code() + “\n”)
.concat(response.message() + “\n”)
.concat(response.body().string());
Log.d(“sendReqTag”, "onSuccess\n " + s);
} catch (IOException e) {
e.printStackTrace();
}
}
}
OkHttp的简单使用方法大致使用如上,其中也有一些细节需要注意:
1、在应用层使用OkHttp,必然会涉及到4个重要元素:
- OkHttpClient类(产生OkHttp客户端实例)
- Request类(请求封装)
- Call类(网络任务封装,并决定是要
同步执行
还是异步执行
,注意,同步请求不
可以放在主线程
中,但是异步请求可以 )- Response类(网络任务执行之后的回调)
2、执行网络请求必须在manifest中申请
INTERNET
权限,不然会抛异常.
3、完整的一个请求执行出去,流程如下图:
OkHttp源码核心类之一:分发器详解
上述,提到Call类,可以选择性执行 同步或者异步请求,但是无论同步异步,都一定会经过一个门户:“分发器” :
索引进源码(okhttp v3.10.0):
虽然用户不需要直接操作分发器,但是 分发器,作为OkHttp
架构的一个门户层,是所有请求的必经之路,其中的代码还是有必要了解细节的。
同步请求
进入分发器 Dispatcher
之后, 会执行 getResponseWithInterceptorChain()
来执行这个Call
任务,得到一个Response
,其中的细节分为两步:
1、
client.dispatcher().executed(this);
,进入源码可以看到 仅仅是执行了runningSyncCalls.add(call);
,将call对象加入到了一个双端队列Deque<RealCall> runningSyncCalls
中。
2、getResponseWithInterceptorChain()
是执行网络请求的核心内容,涉及到拦截器,在这一节上暂时不详述。
同步请求的执行步骤十分简单,将任务加入到 runningSyncCalls列表,并且直接执行核心方法,同步阻塞拿到response。
异步请求
异步请求进入分发器之后,
可能会被加入到
Deque<AsyncCall> runningAsyncCalls
这么一个双端队列中,然后executorService().execute(call);
实际上是用了线程池来执行了这个异步任务。
但是,请注意(还是刚才的enqueue方法代码)这里有一个判断条件 if分支 :
这个条件是否满足,将会直接决定是直接执行这个任务,还是将任务加入到 readyAsyncCalls 双端队列.
那么设置这个条件的目的是什么呢?从变量命名来看:
runningAsyncCalls 执行中的异步任务
runningCallsForHost 同一个域名正在执行的任务数
readyAsyncCalls 预备执行的任务队列(尚未执行)
当正在执行的任务数小于最大值(默认为64)并且,同一个域名正在请求的任务数小于最大值(默认5)时,才会立即执行,否则,这个任务会被加入到 readyAsyncCalls中等待安排。
那么问题来了,readyAsyncCalls中的任务什么时候会被执行?
追踪代码:追踪 readyAsyncCalls 的使用代码,找到遍历
这个队列的地方:
继续追踪,找到了这个 finish方法:
继续追踪finish在哪里调用的,找到两处:
所以,得出结论:
在一个任务(无论同步还是异步)结束之后,分发器中的异步任务,存在两个队列,一个running队列
,一个ready队列
,当running队列
的size小于最大值,并且同一个域名正在执行的任务数小于最大值时,可以直接加入到running队列,立即执行。 如果不满足这条件,这个异步任务就会被加入到 ready队列.在任意一个任务(
无论同步或是异步任务
)执行完毕(无论成败
)之后,就会遍历ready队列
,每次从ready队列
中取出一个任务,判断同时执行的异步任务数是否达到上限,并且同一主机的访问数是否达到上限,如果都满足,就加入到running队列,并且立即执行,不满足,就停止遍历。周而复始,直到所有的异步任务都执行完。
文字不够形象,画个图表示。
关于okhttp的分发器Dispatcher用到的线程池
同步请求,没有用到线程池。
但是异步请求的代码中,有这么一句。
我们知道,为什么这里会用到线程池呢?
1.观察 同步或者异步的call的实例。
那么这个Call
是什么?它是一个接口,它的唯一实现类是RealCall
,
在RealCall
中,异步请求的执行方法,enqueue()
其实是交给了 分发器一个AsyncCall
对象,它继承自NamedRunnable
可命名的Runnable
任务。所以,这里可以用 线程池ExecutorService
来执行这个Runnable
.
进一步观察这个线程池的细节:
它是一个核心线程数为0的线程池,并且使用了一个无容量的阻塞队列作为参数。
其实也不不必自己去创建线程池,而可以直接使用Executors.newCachedThreadPool();
来创建,效果一样。
线程池,系统提供了有多种默认实现
为什么okhttp偏偏选择了这一种?
答:为了实现最大并发量。
详解如下:
既然这里提到了线程池,那么就把线程池的基本机制整理一下:
线程池的构造函数中,有一个阻塞队列参数。
它有3个实现类:ArrayBlockingDeque
/LinkedBlockingDeque
/SynchronousQueue
是我们线程池经常用的。
前面2个都是有容量的,而第三个是无容量的,加入进去,一定会失败。而参照上面线程池的工作流程图,如果加入失败,就会尝试去非核心线程执行任务。这样,便保证了每一个提交进来的异步任务,都会立即尝试去执行,而不是塞入等待队列中等待空闲线程,从而确保了 异步任务的并发。
OkHttp源码核心类之一:拦截器简述
上面讲解分发器的时候,提到了 RealCall类的getResponseWithInterceptorChain()
方法。它是一个网络请求执行的真正核心方法。
进入方法:
- 新建一个拦截器List,并且放入各种拦截器对象
- 将拦截器list,交给RealInterceptorChain,进行责任链模式的调用,最终得出Response.
首先解释一下责任链模式
,它是21种基本设计模式中,行为模式中一种。下面的案例可以很好地解释它:
要如何成为Android架构师?
搭建自己的知识框架,全面提升自己的技术体系,并且往底层源码方向深入钻研。
大多数技术人喜欢用思维脑图来构建自己的知识体系,一目了然。这里给大家分享一份大厂主流的Android架构师技术体系,可以用来搭建自己的知识框架,或者查漏补缺;
对应这份技术大纲,我也整理了一套Android高级架构师完整系列的视频教程,主要针对3-5年Android开发经验以上,需要往高级架构师层次学习提升的同学,希望能帮你突破瓶颈,跳槽进大厂;
最后我必须强调几点:
1.搭建知识框架可不是说你整理好要学习的知识顺序,然后看一遍理解了能复制粘贴就够了,大多都是需要你自己读懂源码和原理,能自己手写出来的。
2.学习的时候你一定要多看多练几遍,把知识才吃透,还要记笔记,这些很重要! 最后你达到什么水平取决你消化了多少知识
3.最终你的知识框架应该是一个完善的,兼顾广度和深度的技术体系。然后经过多次项目实战积累经验,你才能达到高级架构师的层次。
你只需要按照在这个大的框架去填充自己,年薪40W一定不是终点,技术无止境
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!