导读:
- 很多人都看过张鸿洋的这篇文章“Android OkHttp完全解析 是时候来了解OkHttp了”,让我们清晰快速的学习如何使用Okhttp的api。
但我觉得还不够,所以继续了我的学习。
1 OkHttp的好处:
- 对比一下就知道了,以前我用HttpClient和HttpURLConnection(注意URL都是大写)比较多,用在项目的时候,给用户的体验感觉总会出现这样那样的问题,比如跳转到一个新的页面的时候,内容就是加载不出来,简而言之就是不稳定。另外对于一些内存开销和系统开销都需要程序员自己来控制,比如线程池,甚至连接池的处理等等。其次,流量的优化问题自己处理起来也比较麻烦。
OKhttp出来了这些问题都解决了。
下面我们看看官方给的OkHttp的好处:
1.1 支持 SPDY ,共享同一个Socket来处理同一个服务器的所有请求;
那什么是SPDY呢?
它是HTTP的加强(不是取代),基于TCP协议,说白了目的就是让网络请求更快了
SPDY干了哪些事情做到这个的呢?
- 单个TCP连接支持并发的HTTP请求。
- 压缩报头和去掉不必要的头部来减少当前HTTP使用的带宽。
- 定义一个容易实现,在服务器端高效率的协议。通过减少边缘情况、定义易解析的消息格式来减少HTTP的复杂性。
- 强制使用SSL,让SSL协议在现存的网络设施下有更好的安全性和兼容性。
- 允许服务器在需要时发起对客户端的连接并推送数据。
- SPDY已被HTTP/2取代
1.2 如果SPDY不可用,则通过连接池来减少请求延时
什么叫连接池?两个主机建立连接是个很复杂的过程,经过多次数据包的交换,例如TCP的三次握手,每次连接都走这个过程岂不是很耗资源。连接池说白了就是就是为了避免每次都要经历这些连接过程,从而节省了资源,耗时更短。
1.3 无缝的支持GZIP来减少数据流量
小伙伴不知道什么是GZIP,没事,百度百科有讲解。大流量的WEB站点常常使用GZIP的压缩技术来让用户感受更快的速度。这一般是指WWW服务器中安装的一个功能,当有人来访问这个服务器中的网站时,服务器中的这个功能就将网页内容压缩后传输到来访的电脑浏览器中显示出来.一般对纯文本内容可压缩到原大小的40%.这样传输就快了,效果就是你点击网址后会很快的显示出来(优点).当然这也会增加服务器的负载(缺点).
1.4 缓存响应数据来减少重复的网络请求
okhttp只会对get请求进行缓存,post请求是不会进行缓存,这也是有道理的,因为get请求的数据一般是比较持久的,而post一般是交互操作,没太大意义进行缓存。我们get请求有时有不一样的需求,有时需要进行缓存,有时需要直接从网络获取,有时只获取缓存数据,这些处理,okhttp都有帮我们做了,我们做的只需要设置就是了。
2.如何封装这些API
在做项目的时候,网络请求包括get请求,post请求,文件上传等等,如果能有统一的接口来处理这些请求就好了。我研究了一下[张鸿洋](https://github.com/hongyangAndroid/okhttputils)发布在github上的代码,稍微进行了一点改动用在我们的项目之中。需要注意的是,有时候在公司项目中,有些类是需要的,读懂代码之后我们就可以很容易根据自己项目的需求来进行裁剪代码。
2.1 首先回顾一下OkHttp提供的原生接口
(一) get请求
//创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
//创建一个Request
final Request request = new Request.Builder()
.url("https://github.com/hongyangAndroid")
.build();
//new call
Call call = mOkHttpClient.newCall(request);
//请求加入调度
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e)
{
}
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
}
});
(二) post请求
FormEncodingBuilder builder = new FormEncodingBuilder();
builder.add("username","张鸿洋");
Request request = new Request.Builder()
.url(url)
.post(builder.build())
.build();
mOkHttpClient.newCall(request).enqueue(new Callback(){});
仔细观察原生api发现不管是post请求还是get请求,其实只是Request不同而已,其他所需要用到的类都一样。
另外它们Request也有相同的部分,可以抽取一个抽象基类,把相同的属性和方法抽取出来,增强代码的复用性。
下面这张图是代码结构预览图:
下面一一解释封装的思想
builder包下的类:引自Builder构造者模式,目的是为了保存数据
OkHttpRequestBuilder 是抽象基类,抽取了公共属性和方法,例如url(String),headers(HashMap), params
抽象方法public abstract RequestCall build(): 获取RequestCall对象request包下的类:目的是为了构建不同的request
OkHttpRequest: 构建Request的基类 1.通过Request.Builder设置url,tag,以及headers(抽取公共部分);2.抽象方法:buildRequestBody,当子类继承抽象类时,必须实现该方法(利用多态封装);3.build方法:实例化RequestCall(抽取公共部分)
GetRequest:由于是get请求,RequestBody为空
PostFormRequest: post请求,实现requestBodyRequestCall: 实例化Call实例,触发OkHttpUtils执行execute方法
OkHttpUtils: 使用单例模式,保存唯一OkHttpClient对象,执行execute方法
3 所谓的难点:由于异步回调回来之后,依然是在子线程的,方法有很多,介绍一种使用线程池的方式
static class MainThreadExecutor implements Executor
{
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r)
{
handler.post(r); //handler把Runnable弄到UI线程上执行
}
}
//调用
new MainThreadExecutor().execute(new Runnable()
{
@Override
public void run()
{
callback.onResponse(object, id);
callback.onAfter(id);
}
}