文章大纲

一、OkHttp简介
二、OkHttp简单使用
三、OkHttp封装
四、项目源码下载

 

一、OkHttp简介

1. 什么是OkHttp

  一般在Java平台上,我们会使用Apache HttpClient作为Http客户端,用于发送 HTTP 请求,并对响应进行处理。比如可以使用http客户端与第三方服务(如SSO服务)进行集成,当然还可以爬取网上的数据等。OKHttp与HttpClient类似,也是一个Http客户端,提供了对 HTTP/2 和 SPDY 的支持,并提供了连接池,GZIP 压缩和 HTTP 响应缓存功能。

2. OkHttp优点

(1)支持HTTP2/SPDY(SPDY是Google开发的基于TCP的传输层协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验)
(2)socket自动选择最好路线,并支持自动重连,拥有自动维护的socket连接池,减少握手次数,减少了请求延迟,共享Socket,减少对服务器的请求次数
(3)基于Headers的缓存策略减少重复的网络请求
(4)拥有Interceptors轻松处理请求与响应(自动处理GZip压缩)

3. OkHttp功能

(1)一般的get请求
(2)一般的post请求
(3)基于Http的文件上传
(4)文件下载
(5)上传下载的进度回调
(6)加载图片
(7)支持请求回调,直接返回对象、对象集合
(8)支持session的保持
(9)支持自签名网站https的访问,提供方法设置下证书就行
(10)支持取消某个请求

3. OkHttp使用步骤

(1)get请求的步骤,首先构造一个Request对象,参数最起码有个url,当然你可以通过Request.Builder设置更多的参数比如:header、method等。
(2)然后通过request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute()和cancel()等方法。
(3)最后,我们希望以异步的方式去执行请求,所以我们调用的是call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。
(4)onResponse回调的参数是response,一般情况下,比如我们希望获得返回的字符串,
可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()
(5)看到这,你可能会奇怪,竟然还能拿到返回的inputStream,看到这个最起码能意识到一点,这里支持大文件下载,有inputStream我们就可以通过IO的方式写文件。不过也说明一个问题,这个onResponse执行的线程并不是UI线程。的确是的,如果你希望操作控件,还是需要使用handler等
(6)okHttp还支持GJson的处理方式
(7)okhttp支持同步请求和异步请求,Call call = client.newCall(request);为同步请求,发送请求后,就会进入阻塞状态,知道收到响应call.enqueue(new Callback()为异步请求
(8)在okhttp3.Callback的回调方法里面有个参数是Call 这个call可以单独取消相应的请求,随便在onFailure或者onResponse方法内部执行call.cancel()都可以。如果想取消所有的请求,则可以okhttpclient.dispatcher().cancelAll();

二、OkHttp简单使用

1. 进行get请求

/**
* 原始的get请求
*
* @author 吴晓畅
*
*/
public class OkHttpGet { public void get() { //1.okhttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder().
//在这里,还可以设置数据缓存等
//设置超时时间
connectTimeout(15, TimeUnit.SECONDS).
readTimeout(20, TimeUnit.SECONDS).
writeTimeout(20, TimeUnit.SECONDS).
//错误重连
retryOnConnectionFailure(true).
build(); //2构造Request,
//builder.get()代表的是get请求,url方法里面放的参数是一个网络地址
Request.Builder builder = new Request.Builder(); Request request = builder.get().url("http://www.baidu.com/").build(); //3将Request封装成call
Call call = okHttpClient.newCall(request); //4,执行call,这个方法是异步请求数据
call.enqueue(new Callback() { @Override
public void onFailure(Call arg0, IOException arg1) { //失败调用
} @Override
//由于OkHttp在解析response的时候依靠的是response头信息当中的Content-Type字段来判断解码方式
//OkHttp会使用默认的UTF-8编码方式来解码
//这里使用的是异步加载,如果需要使用控件,则在主线程中调用
public void onResponse(Call arg0, Response arg1) throws IOException { //成功调用 }
}); }
}

2. 进行post请求

/**
* 使用okhttp进行post请求
*
* @author 吴晓畅
*
*/
public class OkHttpPost { public void initPost() { //1.okhttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder().
//在这里,还可以设置数据缓存等
//设置超时时间
connectTimeout(15, TimeUnit.SECONDS).
readTimeout(20, TimeUnit.SECONDS).
writeTimeout(20, TimeUnit.SECONDS).
//错误重连
retryOnConnectionFailure(true).
build(); RequestBody requestBodyPost = new FormBody.Builder()
.add("page", "1")
.add("code", "news")
.add("pageSize", "20")
.add("parentid", "0")
.add("type", "1")
.build(); Request requestPost = new Request.Builder()
.url("www.baidu.com")
.post(requestBodyPost)
.build(); okHttpClient.newCall(requestPost).enqueue(new Callback() { @Override
public void onFailure(Call arg0, IOException arg1) {
// TODO Auto-generated method stub } @Override
public void onResponse(Call arg0, Response arg1) throws IOException { //okHttp还支持GJson的处理方式
//在这里可以进行List<bean>和bean处理 } }); } }

3. 进行图片上传和下载

/**
* 使用OkHttp进行图片上传和下载
*
* @author 吴晓畅
*
*/
public class OkHttpPicture
{ public void getPicture() { //1.创建一个okhttpclient对象
OkHttpClient okHttpClient = new OkHttpClient(); //2.创建Request.Builder对象,设置参数,请求方式如果是Get,就不用设置,默认就是Get
Request request = new Request.Builder()
.url("www.baidu.com")
.build(); //3.创建一个Call对象,参数是request对象,发送请求
Call call = okHttpClient.newCall(request); //4.异步请求,请求加入调度
call.enqueue(new Callback() { @Override
public void onFailure(Call arg0, IOException arg1) {
// TODO Auto-generated method stub } @Override
public void onResponse(Call arg0, Response arg1) throws IOException { // //得到从网上获取资源,转换成我们想要的类型
// byte[] Picture_bt = response.body().bytes();
// //通过handler更新UI
// Message message = handler.obtainMessage();
// message.obj = Picture_bt;
// message.what = SUCCESS;
// handler.sendMessage(message); } }); } public void shangChuanPicture() { OkHttpClient mOkHttpClent = new OkHttpClient(); //获取sd卡中的文件
File file = new File(Environment.getExternalStorageDirectory()+"/HeadPortrait.jpg"); MultipartBody.Builder builder = new MultipartBody.Builder()
//设置类型
.setType(MultipartBody.FORM)
//设置正文内容
.addFormDataPart("img", "HeadPortrait.jpg",
RequestBody.create(MediaType.parse("image/png"), file)); RequestBody requestBody = builder.build(); Request request = new Request.Builder()
.url("www.baidu.com")
.post(requestBody)
.build(); Call call = mOkHttpClent.newCall(request); }
}

3. 拦截器使用

什么是拦截器
  首先我们需要了解什么事拦截器。打个比方,镖局押着一箱元宝在行走在一个山间小路上,突然从山上下来一群山贼拦住了镖局的去路,将镖局身上值钱的东西搜刮干净后将其放行。其中山贼相当于拦截器,镖局相当于一个正在执行任务的网络请求,请求中的参数就是镖局携带的元宝。拦截器可以将网络请求携带的参数进行修改验证,然后放行。这里面其实设计了AOP编程的思想(面向切面编程)。
  在介绍拦截器的作用和好处之前,我们还是要回到山贼这个角色上,如果让你做一次山贼,你会在什么地方埋伏?肯定是在镖局必经之路上埋伏。也就是说,拦截器就是在所有的网络请求的必经之地上进行拦截。
(1)拦截器可以一次性对所有的请求和返回值进行修改。
(2)拦截器可以一次性对请求的参数和返回的结果进行编码,比如统一设置为UTF-8.
(3)拦截器可以对所有的请求做统一的日志记录,不需要在每个请求开始或者结束的位置都添加一个日志操作。
(4)其他需要对请求和返回进行统一处理的需求….

OkHttp中拦截器分类
OkHttp中的拦截器分2个:APP层面的拦截器(Application Interception)、网络请求层面的拦截器(Network Interception)
(1)Application Interceptor是在请求执行刚开始,还没有执行OkHttp的核心代码前进行拦截,Application拦截器的作用:
1)不需要担心是否影响OKHttp的请求策略和请求速度。
2)即使是从缓存中取数据,也会执行Application拦截器。
3)允许重试,即Chain.proceed()可以执行多次。(当然请不要盲目执行多次,需要加入你的逻辑判断)
(2)Network Interception是在连接网络之前
1)可以修改OkHttp框架自动添加的一些属性(当然最好不要修改)。
2)可以观察最终完整的请求参数(也就是最终服务器接收到的请求数据和熟悉)

使用注意点
如果对拦截器不是很熟的同学,开发过程中,建议使用Application Interception。这样避免对OkHttp请求策略的破坏。

常见实际场景
(1)对请求参数进行统一加密处理。
(2)拦截不符合规则的URL。
(3)对请求或者返回参数设置统一的编码方式
(4)其它…。

代码实操

public class OkHttpLanJieQi {

    /**
* 应用拦截器
*/
Interceptor appInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //———请求之前要做的事情————
HttpUrl url = request.url();
String s = url.url().toString(); Response response = chain.proceed(request); //———请求之后要做事情————
Log.d("aa","app interceptor:begin"); return response; } }; /**
* 网络拦截器
*/
Interceptor networkInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request(); //———请求之前要做的事情———— Response response = chain.proceed(request); //———请求之后要做事情———— return response;
}
}; /**
* 进行get请求,并配置拦截器
*/
public void initGet() { OkHttpClient okHttpClient = new OkHttpClient
.Builder()
.addInterceptor(appInterceptor)//Application拦截器
.addNetworkInterceptor(networkInterceptor)//Network拦截器
.build(); //2构造Request,
//builder.get()代表的是get请求,url方法里面放的参数是一个网络地址
Request.Builder builder = new Request.Builder(); Request request = builder.get().url("http://www.baidu.com/").build(); //3将Request封装成call
Call call = okHttpClient.newCall(request); //4,执行call,这个方法是异步请求数据
call.enqueue(new Callback() { @Override
public void onFailure(Call arg0, IOException arg1) { //失败调用
} @Override
//由于OkHttp在解析response的时候依靠的是response头信息当中的Content-Type字段来判断解码方式
//OkHttp会使用默认的UTF-8编码方式来解码
//这里使用的是异步加载,如果需要使用控件,则在主线程中调用
public void onResponse(Call arg0, Response arg1) throws IOException { //成功调用 }
}); } }

三、OkHttp封装

1. 自行简单封装

/**
* okhttp操作进行封装
*
* @author 吴晓畅
*
*/
public class OkHttp { public void get(String url, Callback callback) { //1.okhttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder().
//在这里,还可以设置数据缓存等
//设置超时时间
connectTimeout(15, TimeUnit.SECONDS).
readTimeout(20, TimeUnit.SECONDS).
writeTimeout(20, TimeUnit.SECONDS).
addInterceptor(appInterceptor).//Application拦截器
//错误重连
retryOnConnectionFailure(true).
build(); //2构造Request,
//builder.get()代表的是get请求,url方法里面放的参数是一个网络地址
Request.Builder builder = new Request.Builder(); Request request = builder.get().url(url).build(); //3将Request封装成call
Call call = okHttpClient.newCall(request); //4,执行call,这个方法是异步请求数据
call.enqueue(callback); } public void post(String url, List<String> list, Callback callback, RequestBody requestBody) { //1.okhttpClient对象
OkHttpClient okHttpClient = new OkHttpClient.Builder().
//在这里,还可以设置数据缓存等
//设置超时时间
connectTimeout(15, TimeUnit.SECONDS).
addInterceptor(appInterceptor).//Application拦截器
readTimeout(20, TimeUnit.SECONDS).
writeTimeout(20, TimeUnit.SECONDS).
//错误重连
retryOnConnectionFailure(true).
build(); RequestBody requestBodyPost = requestBody; Request requestPost = new Request.Builder()
.url(url)
.post(requestBodyPost)
.build(); okHttpClient.newCall(requestPost).enqueue(callback); } /**
* 应用拦截器
*/
Interceptor appInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //———请求之前要做的事情———— Response response = chain.proceed(request); //———请求之后要做事情———— return response; } };
}

2. Android--OKHttpUtils框架封装

简介
  OKHttpUtils:一个专注于让网络请求更简单的网络请求框架,对于任何形式的网络请求只需要一行代码。它是OKHttp的一次二次封装,封装的目的是让网络请求更加方便。

OKHttpUtils优势
(1)性能高,使用主流的okhttp的进行封装
  OKHttp我们知道它支持http2和socket的重连。自动选择最好的路线,拥有自己维护socket维护的连接池。可以减少TCP的握手次数,同时它拥有队列线程池可以轻松的并发请求。
(2)特有的网络缓存模式
  OKHttpUtils是大多数网络框架不具备的,比如我们公司的网络老板要求不仅在有网的情况下,进行展示网络数据,在无网的情况下使用缓存数据。这时候我们使用普通网络请求,就需要大量的判断。当前是否有网和无网状态,根据不同的状态保存不同的数据。然后再决定是否使用缓存。但是这是一个通用的写法。于是OKHttpUtils使用自动网络缓存模式。让用户只关注数据处理。
(3)方便易用的扩展接口
  可以添加全局的公共参数、全局的拦截器、全局的超时时间,更可以对单个请求定制拦截器。请求参数修改等等。
(4)强大的Cookie的保存策略
  在客户端对Cookie的获取不是一个特别简单的事情,Cookie全程自动管理,并且提供了额外的Cookie管理方法,引入额外的自动管理中,添加任何你想创建的Cookie。

依赖包导入

compile 'com.zhy:okhttputils:2.0.0'

进行get请求

    private String get(String url) throws IOException {

      Request request = new Request.Builder()

          .url(url)//传url

          .build();//创建

      //把request传进client
//execute()执行线程
Response response = client.newCall(request).execute(); return response.body().string();
}

进行post请求

    private String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}

使用okhttp-utils请求单张图片

public void getImage()
{
tv_result.setText("");
String url = "http://images.csdn.net/20150817/1.jpg";
OkHttpUtils
.get()//
.url(url)//
.tag(this)//
.build()//
.connTimeOut(20000)//链接超时
.readTimeOut(20000)//读取超时
.writeTimeOut(20000)//写入超时
.execute(new BitmapCallback()
{
@Override
public void onError(Call call, Exception e, int id)
{
tv_result.setText("onError:" + e.getMessage());
} @Override
public void onResponse(Bitmap bitmap, int id)
{
Log.e("TAG", "onResponse:complete");
iv_icon.setImageBitmap(bitmap);
}
});
}

使用okhttp-utils上传多个或者单个文件

 /**
* 使用okhttp-utils上传多个或者单个文件
*/
public void multiFileUpload()
{ //FileUploadServlet
String mBaseUrl = "http://192.168.3.27:8080/FileUpload/FileUploadServlet"; File file = new File(Environment.getExternalStorageDirectory(), "tupian.jpg");
File file2 = new File(Environment.getExternalStorageDirectory(), "zanghao.jpg");
if (!file.exists())
{
Toast.makeText(OKHttpActivity.this, "文件不存在,请修改文件路径", Toast.LENGTH_SHORT).show();
return;
}
// Map<String, String> params = new HashMap<String, String>();
// params.put("username", "黄敏莹");
// params.put("password", "123"); String url = mBaseUrl;
OkHttpUtils.post()//
.addFile("mFile", "server_tupian.jpg", file)//
.addFile("mFile", "server_zanghao.jpg", file2)//两个addFile就是多文件上传,注释掉一个就是单文件上传
.url(url)
// .params(params)//
.build()//
.execute(new MyStringCallBack());//回调
}

回调处理

/**
* 用于回调
* @author Mloong
*
*/
private class MyStringCallBack extends StringCallback{ @Override
public void onBefore(Request request, int id) {
// TODO Auto-generated method stub
super.onBefore(request, id); setTitle("loading...");
} @Override
public void onAfter(int id) {
// TODO Auto-generated method stub
super.onAfter(id); setTitle("sample-okhttp");
} //出错
@Override
public void onError(Call arg0, Exception e, int arg2) { e.printStackTrace(); tv_result.setText("onError:"+e.getMessage()); } //成功后回调
@Override
public void onResponse(String response, int id) { //显示文本信息
tv_result.setText("onResponse:"+ response); switch (id) {
case 100: Toast.makeText(OKHttpActivity.this, "http", Toast.LENGTH_LONG).show(); break; case 101: Toast.makeText(OKHttpActivity.this, "https", Toast.LENGTH_LONG).show(); break; default:
break;
} } @Override
public void inProgress(float progress, long total, int id) { Log.e(TAG, "inProgress:"+progress); mProgressBar.setProgress((int) (100*progress)); } }

四、项目源码下载

链接:https://pan.baidu.com/s/1f3eZhmfKakrd9zaGzX8_gQ
密码:cv4b

 

Android之OkHttp详解的更多相关文章

  1. android:ToolBar详解

    android:ToolBar详解(手把手教程) 泡在网上的日子 发表于 2014-11-18 12:49 第 124857 次阅读 ToolBar 42 来源 http://blog.mosil.b ...

  2. Android之canvas详解

    首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, y ...

  3. 【转】Android Canvas绘图详解(图文)

    转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...

  4. Android 核心分析 之八Android 启动过程详解

    Android 启动过程详解 Android从Linux系统启动有4个步骤: (1) init进程启动 (2) Native服务启动 (3) System Server,Android服务启动 (4) ...

  5. Android GLSurfaceView用法详解(二)

    输入如何处理       若是开发一个交互型的应用(如游戏),通常需要子类化 GLSurfaceView,由此可以获取输入事件.下面有个例子: java代码: package eoe.ClearTes ...

  6. Android编译过程详解(一)

    Android编译过程详解(一) 注:本文转载自Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359 ...

  7. android屏幕适配详解

    android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要 ...

  8. Android.mk文件详解(转)

    源:Android.mk文件详解 从对Makefile一无所知开始,折腾了一个多星期,终于对Android.mk有了一个全面些的了解.了解了标准的Makefile后,发现Android.mk其实是把真 ...

  9. Android Studio 插件开发详解四:填坑

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78265540 本文出自[赵彦军的博客] 在前面我介绍了插件开发的基本流程 [And ...

随机推荐

  1. zookeeper应用场景-java

    声明,本文是复制别人的文章,感觉还行,原文:http://www.cnblogs.com/xymqx/p/4465610.html 本人热爱技术,跪求有好的技术文章希望大家多多分享,谢谢.... Zo ...

  2. SSM-SpringMVC-20:SpringMVC中处理器方法之返回值void篇

      ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 处理器的方法我们之前做过,返回值为String的,返回值为ModelAndView的,我们这个讲的这个返回 ...

  3. MIT KIT OpenID Connect Demo Client

    Hello world! You are NOT currently logged in. This example application is configured with several pa ...

  4. How nginx "location if" works

    Nginx's if directive does have some weirdness in practice. And people may misuse it when they do not ...

  5. mock打桩之EasyMock

    TDD是测试驱动开发(Test-Driven Development)的英文简称,是敏捷开发中的一项核心实践和技术,也是一种设计方法论.TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代 ...

  6. error LNK2001: 无法解析的外部符号 解决方法

    错误提示:LNK2001 无法解析的外部符号 "public: class el::base::Writer & __cdecl el::base::Writer::construc ...

  7. 传统业务上云:跨AZ容灾架构解析

    本文由  网易云发布. 数字化转型浪潮之下,采用云计算服务提升业务敏捷性.降低运维成本,成为了传统企业的优选方案.网易云资深解决方案架构师张亮通过某物流企业客户的实际案例,分享了传统业务系统在云上的架 ...

  8. 【prufer编码】BZOJ1211 [HNOI2004]树的计数

    Description 给定一棵树每个节点度的限制为di,求有多少符合限制不同的树. Solution 发现prufer码和度数必然的联系 prufer码一个点出现次数为它的度数-1 我们依然可以把树 ...

  9. BZOJ_3653_谈笑风生_树状数组

    BZOJ_3653_谈笑风生_树状数组 Description 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道 高明到哪里去了”. ...

  10. BZOJ_3670_[Noi2014]动物园_KMP

    BZOJ_3670_[Noi2014]动物园_KMP Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的 ...