okhttp
OkHttp 封装了请求和缓存和缓存
OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。
OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。
使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和HttpURLConnection一样的API。如果你用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。
OkHttp 和 fresco retrofit 等第三方库能很好的衔接。
Okhttp作为HTTP引擎,retrofit作为restful业务架构实现;目前retrofit的restful风格规范是趋势。
OkHttp是一个高效的Http客户端
- 支持HTTP2/SPDY黑科技
- socket自动选择最好路线,并支持自动重连
- 拥有自动维护的socket连接池,减少握手次数
- 拥有队列线程池,轻松写并发
- 拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩,LOGGING)
- 基于Headers的缓存策略
注:什么是SPDY
主要对象
- Connections: 对JDK中的socket进行了引用计数封装,用来控制socket连接
- Streams: 维护HTTP的流,用来对Requset/Response进行IO操作
- Calls: HTTP请求任务封装
- StreamAllocation: 用来控制
Connections
/Streams
的资源分配与释放
工作流程的概述
当我们用OkHttpClient.newCall(request)
进行execute/enenqueue
时,实际是将请求Call
放到了Dispatcher
中,okhttp使用Dispatcher进行线程分发,它有两种方法,一个是普通的同步单线程;另一种是使用了队列进行并发任务的分发(Dispatch)与回调,我们下面主要分析第二种,也就是队列这种情况,这也是okhttp能够竞争过其它库的核心功能之一;
Socket管理(StreamAllocation)
经过上一步的分配,我们现在需要进行连接了。我们目前有封装好的Request,而进行HTTP连接需要进行Socket握手,Socket握手的前提是根据域名或代理确定Socket的ip与端口。这个环节主要讲了http的握手过程与连接池的管理,分析的对象主要是StreamAllocation。
Githug: https://github.com/square/okhttp
wiki:https://github.com/square/okhttp/wiki
配置方法:
注意:okhttp内部依赖okio,别忘了同时导入okio
(1)Android Studio:
1 compile 'com.squareup.okhttp:okhttp:2.4.0'
导入okio:
1 compile 'com.squareup.okio:okio:1.5.0'
(2)Eclipse:
可以下载最新的jar okhttp he latest JAR ,添加依赖就可以用了
最新的jar地址:okio the latest JAR
使用:
1 //创建okHttpClient对象 2 OkHttpClient mOkHttpClient = new OkHttpClient(); 3 // 创建Request.Builder post请求方式 4 Request.Builder builder = new Request.Builder().post() 5 .url("https://github.com/hongyangAndroid"); 6 //创建一个Request 7 final Request request = builder.build(); 8 //通过请求request,构造出call 9 Call call = mOkHttpClient.newCall(request);
(1)Request.Builder
通过Request.Builder设置更多的参数比如:
(1) 添加请求头header:
如果它本身存在值,在添加新的value之前,他们会被移除。使用addHeader(name, value)来添加头部不需要移除当前存在的headers。
1 builder.addHeader("SYSVERSION", "1.01");
当写请求头,构造时用header(name, value)来为唯一出现的name设置value。
1 Request.Builder builder = new Request.Builder().post() 2 .url("https://github.com/hongyangAndroid") 3 .header("Cookie", "OkHttpUser");
(2)添加method
请求携带参数:
post方式:
发布表单参数
1 String url = url; 2 // 创建builder 3 FormBody.Builder builder = new FormBody.Builder(); 4 requestBody.add("user", "charles"); 5 requestBody.add("age", "12"); 6 // 创建RequestBody 7 RequestBody requestBody = builder.build(); 8 9 Request request = new Request.Builder().post(requestBody ).url(url).build(); 10 Response response = mOKHttpClient.newCall(request).execute();
发布multipart请求
MultipartBody.Builder可以构建与HTML文件上传表单兼容的复杂请求主体。例如文件上传
视频类:MediaType.parse("application/octet-stream")
1 File file = new File(Environment.getExternalStorageDirectory(), "about.jpg"); 2 3 RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file); 4 5 RequestBody requestBody = new MultipartBuilder() 6 .type(MultipartBuilder.FORM) 7 .addPart(Headers.of( 8 "Content-Disposition", 9 "form-data; name=\"username\""), 10 RequestBody.create(null, "charles")) 11 .addPart(Headers.of( 12 "Content-Disposition", 13 "form-data; name=\"imagefile\"; 14 filename=\"aboutApp.jpg\""), fileBody) 15 .build(); 16 17 Request request = new Request.Builder() 18 .url("http://.../fileUpload") 19 .post(requestBody) 20 .build(); 21 22 Reponse reponse = mOkHttpClient.newCall(request).execute();
get方式:
1 String url = url + "?" + "user=charles" + "&age=12" 2 Request request = new Request.Builder().get().url(url).build(); 3 Response response = mOKHttpClient.newCall(request).execute();
执行call:
(1)异步
调用call.enqueue,将call加入调度队列,等待任务执行完成,在Callback中即可得到结果。
1 // 异步执行call 2 call.enqueue(new Callback() 3 { 4 @Override 5 public void onFailure(Request request, IOException e) 6 { 7 } 8 9 @Override 10 public void onResponse(final Response response) throws IOException 11 { 12 String htmlStr = response.body().string();// 当前线程不是ui线程 13 } 14 });
(2)同步,阻塞方式:
1 Response response = call.execute();
Response:
(1)返回字符串,通过response.body().string()
获取;
(2)返回二进制字节数组,通过response.body().bytes()获取
;
(3)返回inputStream,通过response.body().byteStream()获取 (支持大文件下载);