OkHttp使用详解
2016-09-18 19:53
260 查看
概要
本篇主要讲解OkHttp最基本的使用,如最常见的get和post请求,在本文中post主要介绍的是表单提交方式的请求,文章最后介绍了如何在服务端和客户端设置处理Cookie,客户端给出了两种最常见的方式处理Cookie。在学习Android的过程中,官方集成网络框架就包含了HttpUrlConnection、HttpClient、Volley,其中Volley是android开发团队在2013年Google I/O大会上推出了一个新的网络通信框架,目前Volley中部分代码仍然借助于HttpClient中部分功能,然而HttpClient在Android最新版本6.0中已经被剔除掉了,如果想要使用Volley还必须使用一个第三方的jai包org.apache.http.legacy.jar,再者Volley是针对数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。如果开发中使用HttpUrlConnection则要从头开始封装对应得操作,所以最近转向了一个第三方网络请求框架OkHttp,本文所介绍的示例都是针对OkHttp3.0库。
OkHttp
OkHttp是一个 Java 的 HTTP+SPDY 客户端开发包,同时也支持 Android。需要Android 2.3以上, OkHttp github源码 ,同时还需要一个 okio包OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存;
默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题;
如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求;
从Android4.4开始HttpURLConnection的底层实现采用的是okHttp。
OkHttp的简单使用
OkHttp建立一个网络请求可以是异步的也可以是同步的,大体上分为三个步骤:新建一个OkHttpClient对象,可以直接new一个OkHttpClient,也可以使用建造者模式build一个,事实上new一个新的内部也是调用的build方式构建出来的。
Java
public OkHttpClient() { this(new Builder()); }
public OkHttpClient() { this(new Builder()); }
通过Request.Builder对象新建一个Request对象,仍然使用的是建造者模式;
返回执行结果,同步请求和异步请求在这里才有区别,在执行请求之前,上面两个步骤都是一样的。
OkHttp同步请求
Java//步骤1 OkHttpClient client = new OkHttpClient(); //步骤2 Request request = new Request.Builder().url(url).build(); //步骤3 Response response = client.newCall(request).execute(); if(response.isSuccessful()){ String result = response.body().string(); System.out.println(result); }
//步骤1 OkHttpClientclient = new OkHttpClient(); //步骤2 Requestrequest = new Request.Builder().url(url).build(); //步骤3 Responseresponse = client.newCall(request).execute(); if(res 19941 ponse.isSuccessful()){ String result = response.body().string(); System.out.println(result); }
这里建立的默认请求采用的是get方式请求的,源码如下:
Java
public Builder() { this.method = "GET"; this.headers = new Headers.Builder(); }
public Builder() { this.method = "GET"; this.headers = new Headers.Builder(); }
OkHttp异步请求
与同步请求不同之处就在步骤三中,步骤三代码如下:Java
//步骤3 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { String result = response.body().string(); System.out.println(result); } });
//步骤3 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Callcall, IOException e) { } @Override public void onResponse(Callcall, Responseresponse) throws IOException { String result = response.body().string(); System.out.println(result); } });
注意:虽然这里是异步请求,但是这里的回调函数确是在子线程中执行的回调,在Android开发中如果想将回调放入主线程中,因为只有在主线程中才能更新UI,我们一般会借助于Handler消息机制来处理,以前写过一篇文章Handler机制,一般Looper在哪个线程,它处理的消息就在哪个线程。
Java
//新建一个Handler实例 Handler handler = new Handler(Looper.getMainLooper()); //自定义一个接口回调 public interface RequestCallback { void onStart(); void onSuccess(String result); void onFailure(ErrorType errorType); } //设置转换为主线程的回调 httpClient.newCall(request).enqueue(new Callback() { public void onResponse(Response response) throws IOException { if (response.isSuccessful()) { final String result = response.body().string(); handler.post(new Runnable() { public void run() { callback.onSuccess(result); } }); } } public void onFailure(Request req, final IOException e) { handler.post(new Runnable() { public void run() { callback.onFailure(ErrorType.SERVER); } }); } });
//新建一个Handler实例 Handlerhandler = new Handler(Looper.getMainLooper()); //自定义一个接口回调 public interface RequestCallback { void onStart(); void onSuccess(String result); void onFailure(ErrorTypeerrorType); } //设置转换为主线程的回调 httpClient.newCall(request).enqueue(new Callback() { public void onResponse(Responseresponse) throws IOException { if (response.isSuccessful()) { final String result = response.body().string(); handler.post(new Runnable() { public void run() { callback.onSuccess(result); } }); } } public void onFailure(Requestreq, final IOException e) { handler.post(new Runnable() { public void run() { callback.onFailure(ErrorType.SERVER); } }); } });
get请求url转码
在处理get请求是我们要对url中需要传入的参数进行Encoder处理,主要是为了处理传输过程中的特殊字符如中文或者空格等。Java
public static String buildQueryUrl(String uri, List<KeyValue> params) { StringBuilder queryBuilder = new StringBuilder(uri); if (!uri.contains("?")) { queryBuilder.append("?"); } else if (!uri.endsWith("?")) { queryBuilder.append("&"); } List<KeyValue> queryParams = params; if (queryParams != null) { for (KeyValue kv : queryParams) { String name = kv.key; String value = kv.getValueStr(); if (!TextUtils.isEmpty(name) && value != null) { queryBuilder.append(Uri.encode(name, "utf-8")).append("=").append(Uri.encode(value, "utf-8")).append("&"); } } } if (queryBuilder.charAt(queryBuilder.length() - 1) == '&') { queryBuilder.deleteCharAt(queryBuilder.length() - 1); } if (queryBuilder.charAt(queryBuilder.length() - 1) == '?') { queryBuilder.deleteCharAt(queryBuilder.length() - 1); } return queryBuilder.toString(); }
public static String buildQueryUrl(String uri, List<KeyValue> params) { StringBuilderqueryBuilder = new StringBuilder(uri); if (!uri.contains("?")) { queryBuilder.append("?"); } else if (!uri.endsWith("?")) { queryBuilder.append("&"); } List<KeyValue> queryParams = params; if (queryParams != null) { for (KeyValuekv : queryParams) { String name = kv.key; String value = kv.getValueStr(); if (!TextUtils.isEmpty(name) && value != null) { queryBuilder.append(Uri.encode(name, "utf-8")).append("=").append(Uri.encode(value, "utf-8")).append("&"); } } } if (queryBuilder.charAt(queryBuilder.length() - 1) == '&') { queryBuilder.deleteCharAt(queryBuilder.length() - 1); } if (queryBuilder.charAt(queryBuilder.length() - 1) == '?') { queryBuilder.deleteCharAt(queryBuilder.length() - 1); } return queryBuilder.toString(); }
其中KeyValue就是一个JavaBean,也可以中Map代替,本文KeyValue代码来自xUtils3。
Java
public class KeyValue { public final String key; public final Object value; public KeyValue(String key, Object value) { this.key = key; this.value = value; } public String getValueStr() { return value == null ? null : value.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; KeyValue keyValue = (KeyValue) o; return key == null ? keyValue.key == null : key.equals(keyValue.key); } @Override public int hashCode() { return key != null ? key.hashCode() : 0; } @Override public String toString() { return "KeyValue{" + "key='" + key + '\'' + ", value=" + value + '}'; } }
public class KeyValue { public final String key; public final Object value; public KeyValue(String key, Object value) { this.key = key; this.value = value; } public String getValueStr() { return value == null ? null : value.toString(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; KeyValuekeyValue = (KeyValue) o; return key == null ? keyValue.key == null : key.equals(keyValue.key); } @Override public int hashCode() { return key != null ? key.hashCode() : 0; } @Override public String toString() { return "KeyValue{" + "key='" + key + '\'' + ", value=" + value + '}'; } }
下面是一个url简单的示例:
Java
List<KeyValue> list = new ArrayList<KeyValue>(); list.add(new KeyValue("name", "木子")); list.add(new KeyValue("pwd", "123456")); String uri = "http://192.168.0.117:8080/cookie/get?isLogin=true"; uri = ParamUtils.buildQueryUrl(uri, list);
List<KeyValue> list = new ArrayList<KeyValue>(); list.add(new KeyValue("name", "木子")); list.add(new KeyValue("pwd", "123456")); String uri = "http://192.168.0.117:8080/cookie/get?isLogin=true"; uri = ParamUtils.buildQueryUrl(uri, list);
转码后输入结果为:
http://192.168.0.117:8080/cookie/get?isLogin=true&name=%E6%9C%A8%E5%AD%90&pwd=123456
post请求
这里所讲的post请求,仅仅限制在表单提交中,也就是content-type为” application/x-www-form-urlencoded”的请求,其余的方式如文件上传下次再做介绍。对于post方式提交表单,OkHttp已经封装好了相应的类FormBody来设置表单的参数,示例代码如下:Java
//步骤1 OkHttpClient client = new OkHttpClient(); //步骤2 RequestBody formBody = new FormBody.Builder().add("name", "木子").add("pwd", "123456").build(); Request request = new Request.Builder().url(uri).post(formBody).build(); //步骤3 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { String result = response.body().string(); } });
//步骤1 OkHttpClientclient = new OkHttpClient(); //步骤2 RequestBodyformBody = new FormBody.Builder().add("name", "木子").add("pwd", "123456").build(); Requestrequest = new Request.Builder().url(uri).post(formBody).build(); //步骤3 client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Callcall, IOException e) { } @Override public void onResponse(Callcall, Responseresponse) throws IOException { String result = response.body().string(); } });
OkHttp中Cookie操作
先介绍一下接下来demo的操作流程1、 访问LoginServlet,然后服务器端返回Cookie,在Cookie中设置了isLogin=true,LoginServlet核心处理代码如下:
Java
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); PrintWriter out=resp.getWriter(); //設置cookie,返回isLogin为true Cookie cookie=new Cookie("isLogin", "true"); resp.addCookie(cookie); out.println("login success!"); out.flush(); out.close(); }
protected void doPost(HttpServletRequestreq, HttpServletResponseresp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); PrintWriterout=resp.getWriter(); //設置cookie,返回isLogin为true Cookiecookie=new Cookie("isLogin", "true"); resp.addCookie(cookie); out.println("login success!"); out.flush(); out.close(); }
客户端带着Cookie访问ListServlet,在ListServlet中检查Cookie中isLogin是否为true,若为true则返回成功结果,否则返回错误信息,ListServlet核心处理代码如下:
Java
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); PrintWriter out = resp.getWriter(); // 获取所有的cookie值 Cookie[] cookies = req.getCookies(); if(cookies==null||cookies.length==0){ out.println("list error!"); return; } Cookie cookie = null; for (int i = 0; i < cookies.length; i++) { cookie = cookies[i]; if (cookie.getName().equals("isLogin")) { if(cookie.getValue().equals("true")){ resp.addCookie(cookie); out.println("list success!"); }else{ out.println("list error!"); } break; } } out.flush(); out.close(); }
protected void doPost(HttpServletRequestreq, HttpServletResponseresp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); PrintWriterout = resp.getWriter(); // 获取所有的cookie值 Cookie[] cookies = req.getCookies(); if(cookies==null||cookies.length==0){ out.println("list error!"); return; } Cookiecookie = null; for (int i = 0; i < cookies.length; i++) { cookie = cookies[i]; if (cookie.getName().equals("isLogin")) { if(cookie.getValue().equals("true")){ resp.addCookie(cookie); out.println("list success!"); }else{ out.println("list error!"); } break; } } out.flush(); out.close(); }
OkHttp操作Cookie方式一
该种方式是通过Http请求中的Header来处理Cookie的,服务器端返回的相应头中会有Set-Cookie字段,客户端请求时携带Cookie可以设置Cookie字段。Java
//Login 在响应头中获取请求成功后的Cookie public void onResponse(Call call, Response response) throws IOException { String result = response.body().string(); cookie=response.header("Set-Cookie"); } //List请求时携带客户端Login成功后Cookie Request request = new Request.Builder().url(url).addHeader("Cookie", cookie).build();
//Login 在响应头中获取请求成功后的Cookie public void onResponse(Callcall, Responseresponse) throws IOException { String result = response.body().string(); cookie=response.header("Set-Cookie"); } //List请求时携带客户端Login成功后Cookie Requestrequest = new Request.Builder().url(url).addHeader("Cookie", cookie).build();
OkHttp操作Cookie方式二
事实上OkHttp提供了一种便捷的方式来操作Cookie,通过实现CookieJar接口来自动管理Cookie。Java
public final class JavaNetCookieJar implements CookieJar { private final List<Cookie> allCookies=new ArrayList<Cookie>(); @Override public synchronized void saveFromResponse(HttpUrl url, List<Cookie> cookies) { allCookies.addAll(cookies); } @Override public synchronized List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> result = new ArrayList<Cookie>(); for (Cookie cookie : allCookies) { if (cookie.matches(url)) { result.add(cookie); } } return result; } } //OkHttp中使用CookieJar OkHttpClient client = new OkHttpClient.Builder().cookieJar(new JavaNetCookieJar()).build();
public final class JavaNetCookieJar implements CookieJar { private final List<Cookie> allCookies=new ArrayList<Cookie>(); @Override public synchronized void saveFromResponse(HttpUrlurl, List<Cookie> cookies) { allCookies.addAll(cookies); } @Override public synchronized List<Cookie> loadForRequest(HttpUrlurl) { List<Cookie> result = new ArrayList<Cookie>(); for (Cookiecookie : allCookies) { if (cookie.matches(url)) { result.add(cookie); } } return result; } } //OkHttp中使用CookieJar OkHttpClientclient = new OkHttpClient.Builder().cookieJar(new JavaNetCookieJar()).build();
通过上面方式就可以自定管理Cookie了,但是有一个问题,如果我们客户端使用了多个OkHttpClient,由于CookieJar并不是一个静态属性,所以每一个OkHttpClient都会有一个自己的CookieJar实例,如果已经登录成功后使用一个新的OkHttpClient会发现CookieJar中Cookie为null,当然了如果一个App只有一个OkHttpClient不会出现该问题,解决该问题也很简单,就是设置一个全局的静态变量,每次请求成功后都将Cookie相关信息赋值给该变量就可以了,加入全局静态变量后代码如下:
Java
public final class JavaNetCookieJar implements CookieJar { private final List<Cookie> allCookies=new ArrayList<Cookie>(); @Override public synchronized void saveFromResponse(HttpUrl url, List<Cookie> cookies) { allCookies.addAll(cookies); if(cookies!=null){ //全局静态变量ALL_COOKIES NetUtils.ALL_COOKIES=allCookies; } } @Override public synchronized List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> result = new ArrayList<Cookie>(); for (Cookie cookie : allCookies) { if (cookie.matches(url)) { result.add(cookie); } } if(result.size()==0&&NetUtils.ALL_COOKIES!=null){ result=NetUtils.ALL_COOKIES; } return result; } }
public final class JavaNetCookieJar implements CookieJar { private final List<Cookie> allCookies=new ArrayList<Cookie>(); @Override public synchronized void saveFromResponse(HttpUrlurl, List<Cookie> cookies) { allCookies.addAll(cookies); if(cookies!=null){ //全局静态变量ALL_COOKIES NetUtils.ALL_COOKIES=allCookies; } } @Override public synchronized List<Cookie> loadForRequest(HttpUrlurl) { List<Cookie> result = new ArrayList<Cookie>(); for (Cookiecookie : allCookies) { if (cookie.matches(url)) { result.add(cookie); } } if(result.size()==0&&NetUtils.ALL_COOKIES!=null){ result=NetUtils.ALL_COOKIES; } return result; } }
结束语
本文只讲解了OkHttp的一小部分应用,接下来文件上传和下载还有请求中缓存cache的处理还没有设计,在以后的文章中再详细的介绍。有关Cookie的介绍,在网上也有许多代码,有些将Cookie持久化到了SharedPreferences,有兴趣的可以查看下面这个链接 http://stackoverflow.com/questions/25461792/persistent-cookie-store-using-okhttp-2-on-android ,在本文中也可以在CookieJar的实例中来持久化Cookie,代码就不再介绍了。
相关文章推荐
- OkHttp在Android中使用详解
- OkHttp使用详解——完全版
- OKHttp使用详解
- Android中okhttp3使用详解
- okhttp实战使用详解
- OkHttp使用方法详解
- Retrofit 2.0使用详解,配合OkHttp、Gson,Android最强网络请求框架
- OkHttp使用详解一
- okhttp的详解及其缓存的使用
- okhttp的使用及详解
- Retrofit 2.0使用详解,配合OkHttp、Gson,Android最强网络请求框架
- Okhttp使用详解
- Android okhttp3的使用详解
- OkHttp3使用详解
- Android OkHttp的简单使用和封装详解
- OKHttp使用详解及源码解析
- Android OkHttp 网络请求 使用详解
- (4.2.36.1)HTTP之OkHttp(一): Okhttp3使用详解
- OkHttp使用详解
- OKHttp使用详解,步骤挺详细的,适合初学者使用!