Android使用OKHttp包处理HTTP相关操作的基本用法讲解
OKHttp是一款高效的HTTP客户端,支持连接同一地址的链接共享同一个socket,通过连接池来减小响应延迟,还有透明的GZIP压缩,请求缓存等优势。(GitHub页:https://github.com/square/okhttp)
Android为我们提供了两种HTTP交互的方式:HttpURLConnection 和 Apache HTTP Client,虽然两者都支持HTTPS,流的上传和下载,配置超时,IPv6和连接池,已足够满足我们各种HTTP请求的需求。但更高效的使用HTTP 可以让您的应用运行更快、更节省流量。而OkHttp库就是为此而生。
OkHttp是一个高效的HTTP库:
- 支持 SPDY ,共享同一个Socket来处理同一个服务器的所有请求
- 如果SPDY不可用,则通过连接池来减少请求延时
- 无缝的支持GZIP来减少数据流量
- 缓存响应数据来减少重复的网络请求
- 会从很多常用的连接问题中自动恢复。
如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。
使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果您用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块。
引入
可以通过下载jar包直接导入工程地址
或者通过构建的方式导入
MAVEN:
<dependency> <groupId>com.squareup.okhttp</groupId> <artifactId>okhttp</artifactId> <version>2.4.0</version> </dependency>
GRADLE:
compile 'com.squareup.okhttp:okhttp:2.4.0'
在向网络发起请求的时候,我们最常用的就是GET和POST,下面就来看看如何使用
1. GET
在OKHttp,每次网络请求就是一个Request,我们在Request里填写我们需要的url,header等其他参数,再通过Request构造出Call,Call内部去请求参数,得到回复,并将结果告诉调用者。
package com.jackchan.test.okhttptest; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; import com.squareup.okhttp.Cache; import com.squareup.okhttp.Callback; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import java.io.File; import java.io.IOException; public class TestActivity extends ActionBarActivity { private final static String TAG = "TestActivity"; private final OkHttpClient client = new OkHttpClient(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); new Thread(new Runnable() { @Override public void run() { try { execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } public void execute() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); Response response = client.newCall(request).execute(); if(response.isSuccessful()){ System.out.println(response.code()); System.out.println(response.body().string()); } } }
这个是通过同步的方式去操作网络请求,而android本身是不允许在UI线程做网络请求操作的,因此我们需要自己开启一个线程。
当然,OKHttp也支持异步线程并且有回调返回,有了上面同步的基础,异步只要稍加改动即可
private void enqueue(){ Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { //NOT UI Thread if(response.isSuccessful()){ System.out.println(response.code()); System.out.println(response.body().string()); } } }); }
2、POST
说完GET该介绍些如何使用POST,POST情况下我们一般需要传入参数,甚至一些header,传入参数或者header
比如传入header
Request request = new Request.Builder() .url("https://api.github.com/repos/square/okhttp/issues") .header("User-Agent", "OkHttp Headers.java") .addHeader("Accept", "application/json; q=0.5") .addHeader("Accept", "application/vnd.github.v3+json") .build();
RequestBody formBody = new FormEncodingBuilder() .add("platform", "android") .add("name", "bug") .add("subject", "XXXXXXXXXXXXXXX") .build(); Request request = new Request.Builder() .url(url) .post(body) .build();
Response response = client.newCall(request).execute(); if (response.isSuccessful()) { return response.body().string(); } else { throw new IOException("Unexpected code " + response); }
请求缓存
在网络请求中,缓存技术是一项应用比较广泛的技术,需要对请求过的网络资源进行缓存,而okhttp也支持这一技术,也使用十分方便,前文涨经常出现的OkHttpclient这个时候就要派送用场了。看下面代码
package com.jackchan.test.okhttptest; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; import com.squareup.okhttp.Cache; import com.squareup.okhttp.CacheControl; import com.squareup.okhttp.Call; import com.squareup.okhttp.Callback; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import java.io.File; import java.io.IOException; public class TestActivity extends ActionBarActivity { private final static String TAG = "TestActivity"; private final OkHttpClient client = new OkHttpClient(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); File sdcache = getExternalCacheDir(); int cacheSize = 10 * 1024 * 1024; // 10 MiB client.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize)); new Thread(new Runnable() { @Override public void run() { try { execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } public void execute() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); Response response1 = client.newCall(request).execute(); if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1); String response1Body = response1.body().string(); System.out.println("Response 1 response: " + response1); System.out.println("Response 1 cache response: " + response1.cacheResponse()); System.out.println("Response 1 network response: " + response1.networkResponse()); Response response2 = client.newCall(request).execute(); if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2); String response2Body = response2.body().string(); System.out.println("Response 2 response: " + response2); System.out.println("Response 2 cache response: " + response2.cacheResponse()); System.out.println("Response 2 network response: " + response2.networkResponse()); System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); } }
但有时候即使在有缓存的情况下我们依然需要去后台请求最新的资源(比如资源更新了)这个时候可以使用强制走网络来要求必须请求网络数据
public void execute() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); Response response1 = client.newCall(request).execute(); if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1); String response1Body = response1.body().string(); System.out.println("Response 1 response: " + response1); System.out.println("Response 1 cache response: " + response1.cacheResponse()); System.out.println("Response 1 network response: " + response1.networkResponse()); request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build(); Response response2 = client.newCall(request).execute(); if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2); String response2Body = response2.body().string(); System.out.println("Response 2 response: " + response2); System.out.println("Response 2 cache response: " + response2.cacheResponse()); System.out.println("Response 2 network response: " + response2.networkResponse()); System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); }
response2对应的request变成
request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build();
同样的我们可以使用 FORCE_CACHE 强制只要使用缓存的数据,但如果请求必须从网络获取才有数据,但又使用了FORCE_CACHE 策略就会返回504错误,代码如下,我们去okhttpclient的缓存,并设置request为FORCE_CACHE
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); File sdcache = getExternalCacheDir(); int cacheSize = 10 * 1024 * 1024; // 10 MiB //client.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize)); new Thread(new Runnable() { @Override public void run() { try { execute(); } catch (Exception e) { e.printStackTrace(); System.out.println(e.getMessage().toString()); } } }).start(); } public void execute() throws Exception { Request request = new Request.Builder() .url("http://publicobject.com/helloworld.txt") .build(); Response response1 = client.newCall(request).execute(); if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1); String response1Body = response1.body().string(); System.out.println("Response 1 response: " + response1); System.out.println("Response 1 cache response: " + response1.cacheResponse()); System.out.println("Response 1 network response: " + response1.networkResponse()); request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build(); Response response2 = client.newCall(request).execute(); if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2); String response2Body = response2.body().string(); System.out.println("Response 2 response: " + response2); System.out.println("Response 2 cache response: " + response2.cacheResponse()); System.out.println("Response 2 network response: " + response2.networkResponse()); System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); }
网络操作中,经常会使用到对请求的cancel操作,okhttp的也提供了这方面的接口,call的cancel操作。使用Call.cancel()可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应,将会引发IOException,同时可以通过Request.Builder.tag(Object tag)给请求设置一个标签,并使用OkHttpClient.cancel(Object tag)来取消所有带有这个tag的call。但如果该请求已经在做读写操作的时候,cancel是无法成功的,会抛出IOException异常。
public void canceltest() throws Exception { Request request = new Request.Builder() .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay. .build(); final long startNanos = System.nanoTime(); final Call call = client.newCall(request); // Schedule a job to cancel the call in 1 second. executor.schedule(new Runnable() { @Override public void run() { System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f); call.cancel(); System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f); } }, 1, TimeUnit.SECONDS); try { System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f); Response response = call.execute(); System.out.printf("call is cancel:" + call.isCanceled() + "%n"); System.out.printf("%.2f Call was expected to fail, but completed: %s%n", (System.nanoTime() - startNanos) / 1e9f, response); } catch (IOException e) { System.out.printf("%.2f Call failed as expected: %s%n", (System.nanoTime() - startNanos) / 1e9f, e); } }
上一篇:安卓版微信小程序跳一跳辅助
栏 目:Android代码
下一篇:Android自定义控件ViewGroup实现标签云
本文标题:Android使用OKHttp包处理HTTP相关操作的基本用法讲解
本文地址:http://www.codeinn.net/misctech/61082.html