一概要:
Android已经为我们提供了HttpURLConnection 和 Apache Http Client,能够满足我们各种的Http请求
需求,当时Android SDK依然为我们默认提供了OkHttp。因为OkHttp相对更高效,更省流量。
OkHttp的特点:
1,支持SPDY,共享同一个Socket来处理同一个服务器的所有请求。
2,如果SPDY不可用,则通过连接池来减少请求的延迟。
3,无缝的支持GZIP,来减少数据流量。
4,缓存响应数据,减少重复网络请求。
使用OkHttp需要用到两个jar,OkHttpxxx.jar与Okioxxx.jar
二使用:
Http Get 请求
private static final OkHttpClient client = new OkHttpClient.Builder().build();
private String get(String url) throws IOException{
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
if(response.isSuccessful()){
return response.body().string();
}else{
throw new IOException("Unexpected code " + response);
}
}
Request是OkHttp的访问请求,Builder是辅助类,Response是OkHttp中的响应。
Http Post 请求(提交Json数据)
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
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();
if(response.isSuccessful()){
return response.body().string();
}else{
throw new IOException("Unexpected code " + response);
}
}
Http Post 请求(提交键值对)
private String post(String url, Map<String, String> params) throws IOException{
FormBody.Builder builder = new FormBody.Builder();
Iterator<String> iterator = params.keySet().iterator();
if(iterator.hasNext()){
String key = iterator.next();
//添加键值对
builder.add(key, params.get(key));
}
FormBody body = builder.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使用很方便,但是上面依然有重复代码。这里写一个工具类OkHttpUitl
注意:#OkHttp的官方文档不建议我们创建多个OkHttpClient,因此我们用一个全局变量。
#enqueue是OkHttp为我们提供的异步方法。
public class OkHttpUtil {
private static final int READ_TIME_OUT = 30;
private static final int WRITE_TIME_OUT = 30;
private static final int CONNECTION_TIME_OUT = 30;
private static final OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(READ_TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(WRITE_TIME_OUT, TimeUnit.SECONDS)
.connectTimeout(CONNECTION_TIME_OUT, TimeUnit.SECONDS)
.build();
/**
* 同步任务
*
* @param request
* @return
* @throws IOException
*/
public static Response execute(Request request) throws IOException {
return client.newCall(request).execute();
}
/**
* 异步执行任务
*
* @param request
* @param callback
*/
public static void enqueue(Request request, Callback callback) {
client.newCall(request).enqueue(callback);
}
/**
* 获得String 类型的返回值
* @param url
* @return
* @throws IOException
*/
public static String getStringFromServer(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = execute(request);
if (response.isSuccessful()) {
return response.body().string();
}else{
throw new IOException("Unexpected-code:" + response);
}
}
}
File下载(Get)
/**
* 下载文件
* @param url
* @param path
*/
private void downloadFile(final String url, String path) {
Request request = new Request.Builder().url(url).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtil.i(TAG, "onFailure:" + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
InputStream in = null;
FileOutputStream fos = null;
try {
String path = "mnt/sdcard/Download/temp.jpg";
File file = new File(path);
fos = new FileOutputStream(file);
if (response.isSuccessful()) {
LogUtil.i(TAG, "onResponse success:");
in = response.body().byteStream();
int len;
byte[] buf = new byte[10234];
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} else {
LogUtil.i(TAG, "onResponse code:" + response);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {try {in.close();} catch (Exception e) {}}
if (fos != null) {try {fos.close();} catch (Exception e) {}}
}
}
});
}
File 上传(Post)
private String uploadFile(String url, File file) throws IOException{
RequestBody body = RequestBody.create(MEDIA_TYPE_MARKDOWN, file);
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);
}
}
响应缓存:(缓存响应,在没有网络,或者短时间内重复请求时,读取缓存提高效率,减少流量)
File cacheFile = Util.getCacheFile(context, "okhttp_cache");
Cache cache = new Cache(cacheFile, 10*1024*1024);//10MB
client = new OkHttpClient.Builder()
.cache(cache) //设置缓存了
.build();
private void get(String url) throws IOException {
Request request1 = new Request.Builder().url(url).build();
Response response1 = client.newCall(request1).execute();
if (!response1.isSuccessful()) {
throw new IOException("Unexpected code " + response1);
}
LogUtil.i(TAG, "response:" + response1.body().string());
LogUtil.i(TAG, "response cache:" + response1.cacheResponse());
LogUtil.i(TAG, "response network:" + response1.networkResponse());
Request request2 = new Request.Builder().url(url).build();
Response response2 = client.newCall(request1).execute();
if (!response1.isSuccessful()) {
throw new IOException("Unexpected code " + response2);
}
LogUtil.i(TAG, "response:" + response2.body().string());
LogUtil.i(TAG, "response cache:" + response2.cacheResponse());
LogUtil.i(TAG, "response network:" + response2.networkResponse());
}
注意:#设定一个私有的缓存目录(cacheFile),并限定其大小(10*1024*1024);
#一个缓存目录对应一个OkHttpClient,否侧会出现错误(没有做并发处理)
#上面的第一次请求response1.cacheResponse为null,第二次请求response2.networkResponse为null
#不读取缓存,可以在request build的时设定.cacheControl(CacheControl.ForceNetWork);(等同:)
#只读取缓存的时,设定.cacheControl(CacheControl.ForceCache);
验证:Http Auth
OkHttp会自动尝试一个未验证额请求,如果返回401 Not Authorized时,如果Client设置了Authenticator,会自动
调用一个带证书的新的请求。如果未设置则跳过尝试返回null。
client = new OkHttpClient.Builder()
.cache(cache)
.authenticator(new Authenticator() {
@Nullable
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("username", "password");
return response.request().newBuilder().header("Authorization", credential).build();
}
})
.build();
参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html
OkHttp拓展:OkHttp 使用详情二