第一章 OkHttp 是怎么发出一个请求的?——整体流程概览
OkHttp相关的内容往往会在面试的过程中被一再提及,那么,OkHttp 到底是怎么把一句话 “帮我请求一下百度” 变成一次真正的网络通信?我们一步步来看吧
本章主要目标:
简单了解OkHttp的主体结构以及使用
1、场景想象
大家应该都点过外卖吧,我们不妨用外卖的视角来看下OkHttp的登场角色以及作用过程
OkHttp 概念 | 外卖实体 | 真实动作 | 映射 |
---|---|---|---|
OkHttpClient | 外卖平台总部 | 拥有全部运力、系统、客服、仓库 | 全局配置、连接池、线程池 |
Request | 下单小票 | 用户 App 里下订单,含取货地址+送货地址+备注 | URL、Header、Body |
Call | 一次“跑腿单” | 平台生成唯一单号,可立即派送或排队 | RealCall |
Dispatcher | 外卖调度中心 | 最多可派64辆车,每栋楼最多派5辆 | runningAsyncCalls / perHost limit |
ConnectionPool | 电动车停靠点 | 刚送完 A 栋的电动车不返仓,直接停楼下接下一单,5 分钟没人叫才回仓 | 空闲连接 5 分钟回收 |
Interceptor 链 | 5 道检查口 | ①重试口(地址错?重派) ②加料口(默认给筷子) ③缓存口(店里现成?直接拿) ④取车口(给电动车) ⑤出单口(打印小票) | 5 大拦截器 |
Response | 骑手送达后拍的照片+回执 | 用户点确认收货,平台回传“已送达”照片 | Response 对象 |
2、流程概览
依照先前的设定,先简单借助图了解一下大概的流程,接着一步步拆解整个的过程
①首先,我们需要创建一个okHttpClient
,这是一切的前提
②接着,作为客户,我们需要下单,此时Request
便产生了,Request
肯定需要一些我们的信息
③newCall
给到okHttpClient
,那么就会借助Call
,生成订单
④接下来,平台进行调度,Dispatcher
给了两种方式,对应execute
和enqueue
两种方式
⑤快递员出发需要层层检查,通过Interceptors
来处理
⑥最终快递员将外卖送到用户手上或者放在门口拍照打卡,完成一次完整请求
3、代码层面
现在可能你对整个流程有更加生动的认识了,接下来,我们通过代码再来加深认识
这里我使用的是3.9.0
的版本
build.gradle
里面进行一下配置,好像现在的版本还有一个toml文件
此时,依赖配置完毕,同步一下
首先,看看我们平常直接使用的代码,仅仅是发起一个请求
try { OkHttpClient okHttpClient = new OkHttpClient(); Request request = new Request.Builder() .url("https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action&start=20&limit=20").build(); // 使用try-with-resources自动关闭Response,避免内存泄漏 try (Response response = okHttpClient.newCall(request).execute()) { Log.d(TAG, "response=\n" + response.body().string()); }
} catch (Exception e) { e.printStackTrace();
}
这便是同步请求的写法,使用execute()
进行请求
创建了OkHttpClient
对象,并且给Request
添加了信息,这里使用的是豆瓣电影的接口
使用newCall()
创建请求,执行结果给到Response
注意,同步请求会阻塞当前的线程,直到结果返回,因此不会在主线程调用,否则很容易造成ANR,通常只会另外开辟线程使用或者用于测试代码
有一个初步的印象,我们再来看一看异步请求
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder() .url("https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action&start=20&limit=20").build();
okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { try { Log.d(TAG, "response=\n" + response.body().string()); } finally { response.close(); // 确保Response被关闭 } }
});
同样的业务需求,使用enqueue()
则进行异步请求,不会阻塞,获得响应时回调
通常情况下都是采用异步请求的方式
这便是最简单的使用,通过response.body().string()
获取响应结果
这两者主要的区别,在于是调用了execute()
还是调用了equeue()
,后面几章将会深入探讨里面的内容
参考:
https://github.com/square/okhttp