Android系统提供了两种HTTP通信类,HttpURLConnection和HttpClient
尽管Google在大部分安卓版本中推荐使用HttpURLConnection,但是这个类相比HttpClient实在是太难用,太弱爆了。OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。使用时要求jdk及1.7以上。
下载:https://github.com/square/okhttp
okhttp内部依赖okio,需要同时导入okio
https://search.maven.org/remote_content?g=com.squareup.okio&a=okio&v=LATEST
也可以使用构建的方式进行导入,会自动从框架库中下载
MAVEN:
<dependency>
<groupId>com.squareup.okhttpgroupId>
<artifactId>okhttpartifactId>
<version>2.4.0version>
dependency>
GRADLE
compile 'com.squareup.okhttp:okhttp:2.4.0'
一般的get请求
一般的post请求
基于Http的文件上传
文件下载
加载图片
支持请求回调,直接返回对象、对象集合
支持session的保持
okhttp网络请求分为同步请求和异步请求。
异步请求执行方法:
Call call = client.newCall(request);
call.enqueue(new Callback(){...});
异步请求数据示例
private void okhttpA(String url) {
// 1.需要一个OkHttpClient对象,最好一个app中只实例化一个该对象。
OkHttpClient client = new OkHttpClient();
// 2.新建一个请求
Request request = new Request.Builder().url(url).build();
// 3.执行请求,获得响应的结果
Call call = client.newCall(request);
// 4.加入调度
final TextView tv = new TextView(this);
call.enqueue(new Callback() {
@Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
final String str = response.body().string();
runOnUiThread( new Runnable() {
public void run() {
tv.setText(str);
}
});
} else {
throw new IOException("Unexpected code " + response);
}
}
@Override
public void onFailure(Request arg0, IOException arg1) {
}
});
}
同步请求执行方法:
Call call = client.newCall(request);
call.execute();
同步请求数据示例
private String okhttpB(String url) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
Call call = client.newCall(request);
Response response = call.execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
下面主要示例都以异步为主:
1.一般的get请求
private void okhttpGet(String url){
//1.需要一个OkHttpClient对象,最好一个app中只实例化一个该对象。
OkHttpClient client = new OkHttpClient();
//2.新建一个请求
Request request = new Request.Builder().url(url).build();
//3.执行请求,获得响应的结果
Call call = client.newCall(request);
//4.加入调度
call.enqueue(new Callback() {
@Override
public void onResponse(Response arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onFailure(Request arg0, IOException arg1) {
// TODO Auto-generated method stub
}
});
}
2.post提交,提交各种类型数据
这种提交形式和服务器有关,有些服务器不支持这种数据处理。
①提交json类型字符串
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private void okhttpPostWithJson(String url) {
String json =""; //一个Json字符串
// 1.创建OkHttpClient
OkHttpClient client = new OkHttpClient();
// 2.新建请求体,放入参数
RequestBody body = RequestBody.create(JSON, json);
// 3.新建请求
Request request = new Request.Builder().url(url).post(body).build();
// 4.new call
Call call = client.newCall(request);
//5.监听回调
call.enqueue(new Callback() {
@Override
public void onResponse(Response arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onFailure(Request arg0, IOException arg1) {
// TODO Auto-generated method stub
}
});
}
②这个例子提交了一个markdown文档到web服务,以HTML方式渲染markdown。因为整个请求体都在内存中,因此避免使用此api提交大文档(大于1MB)。
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
③使用流的方式,POST提交请求体。请求体的内容(也就是携带的数据体)由流写入产生。这个例子是流直接写入Okio的BufferedSink。你的程序可能会使用OutputStream,你可以使用BufferedSink.outputStream()来获取一个OutputStream实例。
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void okhttpPostStream() throws Exception {
//1.携带的数据体
RequestBody requestBody = new RequestBody() {
//文件类型
@Override
public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
//写入的数据内容
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("Numbers\n");
sink.writeUtf8("-------\n");
for (int i = 2; i <= 997; i++) {
sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
}
}
private String factor(int n) {
for (int i = 2; i < n; i++) {
int x = n / i;
if (x * i == n)
return factor(x) + " × " + i;
}
return Integer.toString(n);
}
};
//2.请求体
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
//3.执行请求,获得返回结果
Response response = client.newCall(request).execute();
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
④上传一个本地文件
public static final MediaType MEDIA_TYPE_MARKDOWN= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void okhttpPostFile() throws Exception {
File file = null;
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
//sd卡不存在
return;
}
file = new File(Environment.getExternalStorageDirectory()+"/readme.txt");
if(!file.exists()){
//文件不存在
return;
}
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
3.post提交,参数为键值对
private void okhttpPostWithParams(String url) throws IOException {
OkHttpClient client = new OkHttpClient();
RequestBody body = new FormEncodingBuilder()
.add("id", "154")
.add("name", "Jack")
.add("password", "123456")
.build();
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onResponse(Response arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onFailure(Request arg0, IOException arg1) {
// TODO Auto-generated method stub
}
});
}
4.提取响应头信息
private final OkHttpClient client = new OkHttpClient();
public void okhttpGetHeader() throws Exception {
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();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println("Server: " + response.header("Server"));
System.out.println("Date: " + response.header("Date"));
System.out.println("Vary: " + response.headers("Vary"));
}
5post提交分块请求
MultipartBuilder可以构建复杂的请求体,与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这块请求,例如他的Content-Disposition。如果Content-Length和Content-Type可用的话,他们会被自动添加到请求头中。
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void okhttpPostMultipart() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
6.使用Gson来解析JSON响应
Gson是一个在JSON和Java对象之间转换非常方便的api。这里我们用Gson来解析JSON响应。
注意:ResponseBody.charStream()使用响应头Content-Type指定的字符集来解析响应体。默认是UTF-8。
private final OkHttpClient client = new OkHttpClient();
private final Gson gson = new Gson();
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://api.github.com/gists/c2a7c39532239ff261be")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Gist gist = gson.fromJson(response.body().charStream(), Gist.class);
SetString, GistFile>> entrySet = gist.files.entrySet();
for(Entry<String, GistFile> entry:entrySet){
System.out.println(entry.getKey());
System.out.println(entry.getValue().content);
}
}
static class Gist {
Map<String, GistFile> files;
}
static class GistFile {
String content;
}
7.图片下载
byte[] data = response.body().bytes();
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
8.文件下载
InputStream is = response.body().byteStream();
byte[] buffer = new byte[1024];
File file = new File(Environment.getExternalStorageDirectory(), "aa.mp3");
FileOutputStream fos = new FileOutputStream(file);
while( (is.read(buffer)) != -1 ){
fos.write(buffer, 0, buffer.length);
fos.flush();
}
is.close();
fos.close();
9.其他
①取消一个call
call.cancel();
②设置超时时间
client = new OkHttpClient();
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setWriteTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
③克隆一个client,基本配置和原来的一样,但是我们可以在克隆之后的client进行修改。
private final OkHttpClient client = new OkHttpClient();
public void okhttpClone(){
Request request = new Request.Builder()
.url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
.build();
//克隆OkHttpClient
try {
OkHttpClient client1 = client.clone();
client1.setReadTimeout(500, TimeUnit.MICROSECONDS);
Call call1 = client1.newCall(request);
Response response1;
response1 = call1.execute();
System.out.println("Response 1 succeeded: " + response1);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Response 1 failed: " + e);
}
try {
OkHttpClient client2 = client.clone();
client2.setReadTimeout(3000, TimeUnit.MICROSECONDS);
Call call2 = client2.newCall(request);
Response response2;
response2 = call2.execute();
System.out.println("Response 2 succeeded: " + response2);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Response 2 failed: " + e);
}
}
参考文章:http://www.cnblogs.com/ct2011/p/3997368.html