前言

讲完了Volley,我们接下来看看目前比较火的网络框架OkHttp, 它处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP,此外OkHttp还处理了代理服务器问题和SSL握手失败问题。

1.使用前准备

eclipse引入jar包地址:
okhttp-2.7.5.jar
okio-1.7.0.jar

Android Studio 配置gradle:

  compile 'com.squareup.okhttp:okhttp:2.7.5'compile 'com.squareup.okio:okio:1.7.0'

2.异步GET请求

最简单的get请求,老规矩请求百度:

      private void getAsynHttp() {//创建okHttpClient对象OkHttpClient mOkHttpClient = new OkHttpClient();final Request request = new Request.Builder().url("http://www.baidu.com").build();Call call = mOkHttpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {}@Overridepublic void onResponse(final Response response) throws IOException {String str = response.body().string();Log.i("wangshu", str);runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(getApplication(), "请求成功", Toast.LENGTH_SHORT).show();}});}});}

运行程序log打印出来的是百度首页的html文件,基本的步骤很简单,就是创建OkHttpClient、Request和Call,最后调用Call的enqueue()方法。但是每次这么写肯定是很麻烦,肯定是要进行封装的。需要注意的是onResponse回调并不是在UI线程。

3.同步GET请求

 private String getSyncHttp() throws IOException{OkHttpClient mOkHttpClient = new OkHttpClient();//创建请求Requestfinal Request request = new Request.Builder().url("http://www.baidu.com").build();Call call = mOkHttpClient.newCall(request);Response mResponse=call.execute();if (mResponse.isSuccessful()) {return mResponse.body().string();} else {throw new IOException("Unexpected code " + mResponse);}}

同步Get请求和异步调用区别就是调用了call的execute()方法。

4.异步POST请求

    private void postAsynHttp() {OkHttpClient mOkHttpClient = new OkHttpClient();RequestBody formBody = new FormEncodingBuilder().add("size", "10").build();Request request = new Request.Builder().url("http://api.1-blog.com/biz/bizserver/article/list.do").post(formBody).build();Call call = mOkHttpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {}@Overridepublic void onResponse(Response response) throws IOException {String str = response.body().string();Log.i("wangshu", str);runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();}});}});}

post与get不同的就是要要创建RequestBody并传进Request中,同样onResponse回调不是在UI线程。

5.请求缓存设置

首先我们设置缓存路径和大小并设置给OkHttpClient:

 mOkHttpClient = new OkHttpClient();File sdcache = getExternalCacheDir();int cacheSize = 10 * 1024 * 1024;mOkHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));

接下来异步GET请求baidu:

 private void getAsynHttp() {//创建请求Requestfinal Request request = new Request.Builder().url("http://www.baidu.com").build();Call call = mOkHttpClient.newCall(request);call.enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {}@Overridepublic void onResponse(final Response response) throws IOException {if (null != response.cacheResponse()) {String str = response.cacheResponse().toString();Log.i("wangshu", "cache---" + str);} else {response.body().string();String str=response.networkResponse().toString();Log.i("wangshu", "network---" + str);}runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();}});}});}

第一次请求会请求网络得到数据,第二次以及后面的请求则会从缓存中取出数据:

当然也有种情况是有的请求每次都需要最新的数据,则在创建Request,来设置cacheControl为“CacheControl.FORCE_NETWORK”,用来表示请求会一直请求网络得到数据:

  final Request request = new Request.Builder().url("http://www.baidu.com").cacheControl(CacheControl.FORCE_NETWORK).build();

运行程序结果为:

6.设置超时时间

另外我们也需要设置超时的时间用来处理各种网络超时的情况,超时的原因可能是网络问题也可能是服务器响应慢等问题,OkHttp当然不会忽略这一点,它支持连接、读取和写入超时的时间设置:

        mOkHttpClient = new OkHttpClient();mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS);mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS);mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS);

7.取消请求

使用call.cancel()可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应,将会引发IOException。当用户离开一个应用时或者跳到其他界面时,使用Call.cancel()可以节约网络资源,另外不管同步还是异步的call都可以取消。
也可以通过tags来同时取消多个请求。当你构建一请求时,使用RequestBuilder.tag(tag)来分配一个标签。之后你就可以用OkHttpClient.cancel(tag)来取消所有带有这个tag的call。

为了模拟这个场景我们首先创建一个定时的线程池:

   private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

接下来的代码为:

 private  void cancel(){final Request request = new Request.Builder().url("http://www.baidu.com").cacheControl(CacheControl.FORCE_NETWORK).build();Call call=null;call = mOkHttpClient.newCall(request);final Call finalCall = call;//100毫秒后取消callexecutor.schedule(new Runnable() {@Override public void run() {finalCall.cancel();}}, 100, TimeUnit.MILLISECONDS);call.enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {}@Overridepublic void onResponse(final Response response) {if (null != response.cacheResponse()) {String str = response.cacheResponse().toString();Log.i("wangshu", "cache---" + str);} else {try {response.body().string();} catch (IOException e) {Log.i("wangshu", "IOException");e.printStackTrace();}String str = response.networkResponse().toString();Log.i("wangshu", "network---" + str);}}});Log.i("wangshu", "是否取消成功"+call.isCanceled());}

100毫秒后调用call.cancel(),为了能让请求耗时,我们设置每次请求都要请求网络,运行程序并且不断的快速点击发送请求按钮:

很明显每次cancel()都失败了,仍旧成功的访问了网络,在cancel()时已经有读写操作了所以会报IOException。每隔100毫秒来调用call.cancel()显然时间间隔太长,我们设置为1毫秒并不断的快速的点击发送请求按钮:

没有请求网络的log,几乎每次都取消成功了。

8.关于封装

如果每次请求网络都需要写重复的代码绝对是令人头疼的,网上也有很多对OkHttp封装的优秀开源项目,功能也非常强大,封装的意义就在于更加方便的使用,具有拓展性,但是对OkHttp封装最需要解决的是以下的两点:

  1. 避免重复代码调用
  2. 将请求结果回调改为UI线程

根据以上两点,我们也简单封装一下,在此只是举个例子,如果想要使用OkHttp封装的开源库,推荐使用OkHttpFinal。
首先呢我们写一个抽象类用于请求回调:

public abstract class ResultCallback<T>
{public abstract void onError(Request request, Exception e);public abstract void onResponse(Response response);
}

接下来封装OkHttp,并实现了异步GET请求:

public class OkHttpEngine {private static OkHttpEngine mInstance;private OkHttpClient mOkHttpClient;private Handler mHandler;public static OkHttpEngine getInstance() {if (mInstance == null) {synchronized (OkHttpEngine.class) {if (mInstance == null) {mInstance = new OkHttpEngine();}}}return mInstance;}private OkHttpEngine() {mOkHttpClient = new OkHttpClient();mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS);mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS);mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS);mHandler = new Handler();}public OkHttpEngine setCache(Context mContext) {File sdcache = mContext.getExternalCacheDir();int cacheSize = 10 * 1024 * 1024;mOkHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));return mInstance;}/*** 异步get请求* @param url* @param callback*/public void getAsynHttp(String url, ResultCallback callback) {final Request request = new Request.Builder().url(url).build();Call call = mOkHttpClient.newCall(request);dealResult(call, callback);}private void dealResult(Call call, final ResultCallback callback) {call.enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {sendFailedCallback(request, e, callback);}@Overridepublic void onResponse(final Response response) throws IOException {sendSuccessCallback(response, callback);}private void sendSuccessCallback(final Response object, final ResultCallback callback) {mHandler.post(new Runnable() {@Overridepublic void run() {if (callback != null) {callback.onResponse(object);}}});}private void sendFailedCallback(final Request request, final Exception e, final ResultCallback callback) {mHandler.post(new Runnable() {@Overridepublic void run() {if (callback != null)callback.onError(request, e);}});}});}
}

原理很简单就是,写一个双重检查模式的单例,不了解双重检查模式的请查看设计模式之单例模式的七种写法这篇文章。在开始创建的时候配置好OkHttpClient,在请求网络的时候用Handler将请求的结果回调给UI线程。

最后调用这个OkHttpEngine的getAsynHttp()方法:

  OkHttpEngine.getInstance().getAsynHttp("http://www.baidu.com", new ResultCallback() {@Overridepublic void onError(Request request, Exception e) {}@Overridepublic void onResponse(Response response) {String str = response.networkResponse().toString();Log.i("wangshu", str);Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();}});

使用起来简单多了,而且请求结果回调是在UI线程的。下一篇我们会讲到OkHttp3,来看看它与OkHttp2.x之间的使用方式上有什么区别。

github源码下载

Android网络编程5之OkHttp2.x用法全解析相关推荐

  1. Android网络编程(一)HTTP协议原理

    相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 And ...

  2. Android网络编程系列 一 Socket抽象层

    在<Android网络编程>系列文章中,前面已经将Java的通信底层大致的描述了,在我们了解了TCP/IP通信族架构及其原理,接下来我们就开始来了解基于tcp/ip协议层的Socket抽象 ...

  3. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包 权限 地址 套接字 相关类 简介

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

  4. 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api

    Android 网络编程相关的包 : 9 包, 20 接口, 103 类, 6 枚举, 14异常; -- Java包 : java.net 包 (6接口, 34类, 2枚举, 12异常); -- An ...

  5. 【Android】Android网络编程概述

    Android网络编程概述 原文来自:http://blog.csdn.net/kieven2008/article/details/8210737 首先,应该了解的几个问题: 1)Android平台 ...

  6. Android网络编程http派/申请服务

    最近的研究Android网络编程知识,这里有一些想法,今晚学习.与您分享. 在实际的应用程序的开发非常需要时间appserver请求数据,那么app怎样发送请求呢?以下的代码就是当中的一种情况.使用H ...

  7. Android网络编程(八) 之 HttpURLConnection原理分析

    1 使用回顾 我们在前面博文<Android网络编程(四) 之 HttpClient与HttpURLConnection>中已经对HttpURLConnection的使用进行过介绍.今天我 ...

  8. Kotlin第五章: android网络编程

    1. Android网络编程 OkHttp OkHttp是一个高效的HTTP客户端,它的横空出世,让其他的网络请求框架都变得黯然失色. Retrofit Retrofit是一个基于OkHttp的RES ...

  9. Android网络编程只局域网传输文件

    Android网络编程只局域网传输文件 首先创建一个socket管理类,该类是传输文件的核心类,主要用来发送文件和接收文件 具体代码如下: ```java1 package com.jiao.file ...

最新文章

  1. Count Primes(leetcode204)
  2. Hyperloop,让发布简洁高效
  3. Eclipse的两个hibernate plugin
  4. 《算法图解》——狄克斯特拉算法
  5. java简单代码_几个简单的入门JAVA代码
  6. Build/Launch EDKII emulator in Windows and Linux:编译/运行Windows和Linux环境下EDKII模拟器[4]
  7. 压倒eBay 挑战亚马逊 Shopify到底厉害在哪儿?
  8. matlab求矩阵的非,matlab矩阵非零个数 Matlab如何提取非零元素
  9. 车架号VIN码识别,合格证,购车发票,房产证,车牌,驾驶证,行驶证,征信报告等等识别 从易鑫、大搜车、淘车网,看汽车金融发展新模式...
  10. mysql error 1_mysql 启动错误(InnoDB: Operating system error number 1
  11. Linux 复制、粘贴快捷键
  12. Surround360 Render目录下RENDER文档——中文翻译
  13. WPS文字 JSA 学习笔记 - 批量设置表格
  14. Android Studio制作.9.png图片
  15. 全国计算机等级考试二级教程:c语言程序设计(2013年版),全国计算机等级考试二级教程:C语言程序设计(2013年版)...
  16. R中Error in gsub(“`“, ““, x, fixed = TRUE) : input string 11 is invalid in this locale
  17. 视频正在“吞噬”互联网 欢迎来到后文本的未来?
  18. “国密证书全生态应用战略研讨会”在深圳隆重召开
  19. 游戏开放平台开发历程
  20. 大厂经典面试系列之二:京东Java面试【建议关注收藏订阅,你早晚会用上】

热门文章

  1. 采用Locust对grpc协议进行压测
  2. 搭建第一个Docker
  3. linux环境配置sonarqube
  4. Python21天打卡Day11-dict和json格式互转
  5. php商品秒杀时间代码,Thinkphp5+Redis实现商品秒杀代码实例讲解
  6. 接口自动化测试(Python+Requests+Unittest)
  7. 小白也能看得懂的服务端性能测试指标及问题排查
  8. 学习软件测试你不了解这7点你算是白学了...
  9. 如何备份数据库的某张表_详解mysql数据库如何用mysqldump实现单表备份
  10. python初体验-hello world答案_Anaconda上的python3初体验