对于okhttp在现在项目中的普及程度已经不言而喻啦,基本上现在网络请求都会基于它去进行封装,而非前几年用Android的网络框架HttpURLConnection和Apache HttpClient去进行底层网络访问的封装了,就目前而言它应该是最火热的网络请求开源项目了,既然这么多公司的项目都采用它确定是有缘由的,因此百度百科上对它的优劣列举了下:android
另外再闲扯一下,它是由移动支付Square公司贡献的,说到Square,我想有一位Android大神不得不提,看图说话:面试
其中它对okhttp的贡献至关之大:网络
好了,回到正题,对于这么优秀的一个开源框架,若是只是停留在如何使用它貌似确实有点浪费了,另外还有一个缘由就是现在android面试并不是前几年了,对于技术的要求也愈来愈高了,而面试中只问你如何在项目中使用主流的三方开源框架我想是愈来愈少了,因此,接下来准备一点点去从源码的角度去分析它的机制,固然因为它的代码量巨大,要想所有搞明白那也挺费尽的,重点是从其流程原理上进行有针对性的分析。app
在正式进行源码分析以前先来看一下使用okhttp如何网络请求,而它提供了两种请求方式:同步和异步,下面开始。框架
同步请求:异步
首先加入okhttp的官方依赖,这里采用okhttp3.9.0这个版本进行学习,首先在gradle中加入依赖:ide
接着在界面中增长一个按钮,点击它则进行同步请求:源码分析
而具体代码的实现过程以下:学习
一、建立OkHttpClient对象:gradle
对于HttpClient咱们都很熟悉,这是以前Android库中的网络使用对象,回忆一下:
而在使用okhttp时,第一步其实也是相似,须要建立OkHttpClient,以下:
上面这句代码就已经将OkHttpClient建立完了么?试想一下对于网络请求是否是得配置不少的一些参数,如网络超时等,而对于参数的配置最适合最优雅的方式则是采用Builder模式,而OkHttpClient对于参数的构建就是这么搞的,因此将其改成用Builder模式去构建以下:
其中设置了5秒的读取超时时间,固然还能够设置很是多的参数,点一下就能够看到:
其怎么使用Builder模式,这个以后在源码分析中会详细去阅读的,不过这里能够简单的瞅一眼大体构建过程,那就打开OkHttpClient的源代码:
而针对每一个参数定义了一个对外调用的方法,方法的重点是返回Builder这个内部类对象自身,这样就能够不断的以点的方式链式的进行参数的配置,以我们已经使用到的readTimeout()为例:
当全部参数都设置完毕以后,最后调用它的build()方法进行OkHttpClient对象的构建,以下:
基于上已经分析清楚了使用Builder模式的步骤,在实际开发中若是遇到有不少参数要进行配置利用这个模式体验上会比较好,能够校仿一下。
二、建立Request对象:
对于这个对象的建立也是采用Builder方式进行构建,可见Builder模式仍是至关好用的,由于在这个对象中也是有一些参数须要进行配置,如URL、请求方式等,因此下面就不过多的解释了,直接上代码:
上面是采用get方式,对比一下我们传统的代码,其实也差很少,传统代码中用HttpGet来直观的表达请求:
三、将Request封装成Call对象:
对于Request和OkHttpClient如何关连起来呢?这里就它这种关联封装成了Call对象了,以下:
四、调用Call的execute()发送同步请求:
最后我们运行看一下效果,固然在运行以前须要给app加入访问网络的权限,这里就很少说了:
足以证实它确实是以同步的方式去请求网络的,要想不报错那固然得将这个请求放到子线程喽,因而乎:
再次编译运行:
异步请求:
先增长一个异步请求的button:
相比上面的同步请求,异步请求的实现步骤基本上差很少,以下:
一、建立OkHttpClient对象:
二、建立Request对象:
三、将Request封装成Call对象:
四、调用Call的enqueue方法进行异步请求:
可是,其实OkhttpClient对于APP而言只要建立一次既可,并不用每次请求就得建立一下它,因此能够将它提取出来,由每一个不一样的请求共享它:
public class MainActivity extends AppCompatActivity { private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder() .readTimeout(5, TimeUnit.SECONDS) .build(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /** * 同步请求 */ public void synRequest(View view) { new Thread(new Runnable() { @Override public void run() { //二、建立Request对象 final Request request = new Request.Builder().url("http://www.baidu.com") .get().build(); //三、将Request封装成Call对象 Call call = OK_HTTP_CLIENT.newCall(request); //四、调用Call的execute()发送同步请求 try { Response response = call.execute(); Log.e("cexo", response.body().string()); } catch (IOException e) { e.printStackTrace(); } } }).start(); } /** * 异步请求 */ public void asycRequest(View view) { //二、建立Request对象 final Request request = new Request.Builder().url("http://www.baidu.com") .get().build(); //三、将Request封装成Call对象 Call call = OK_HTTP_CLIENT.newCall(request); //四、调用Call的enqueue方法进行异步请求 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e("cexo", "request failed:" + e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { Log.e("cexo", "request successed:" + response.body().string()); } }); } }
编译运行:
可见确实是在子线程执行的,也说明是异步请求。
【注意】:异步请求回调onResponse()和onFailure()方法都是在子线程执行的,这个是比较容易忽视的,下面来实验下:
编译运行:
总结:
对于OkHttp的同步和异步请求须要记住的是:
一、发起请求的方法调用:同步请求是调用Call.execute();异步请求是调用Call.enqueue()。
二、阻塞线程与否:同步阻塞、异步不阻塞。