Android网络框架OKHTTP-实践篇

android网络请求是个耗时的操作,一定要在子线程中运行,添加网络权限,目前有很多流行的网络框架。比如okhttp,volley,xutils等等。今天主要介绍okhttp的使用,后续分享给多,比如socket网络请求,文件上传下载。

android网络请求是个耗时的操作,一定要在子线程中运行,添加网络权限,目前有很多流行的网络框架。比如okhttp,volley,xutils等等。今天主要介绍okhttp的使用,后续分享给多,比如socket网络请求,文件上传下载。

一,HTTP协议的主要特点

HTTP协议的主要特点可概括如下:
1.支持客户/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
详见原文:HTTP协议详解(真的很经典)

二,OKHttp介绍

An HTTP & HTTP/2 client for Android and Java applications. For more information see the website and the wiki.前往OkHttp官网
使用okhttp很简单,它的请求/响应 API设计,运用了流利的builder,确保方式多样而又固定,支持异步请求和回调。它支持android 2.3或以上,jdk版本要求不低于1.7。

okhttp的主要特点:

  1. HTTP/2支持共享一个socket,发送多个请求给相同的主机。
  2. 连接池减少了请求的潜在因素。
  3. 明显的GZIP压缩下载大小。
  4. 响应缓存避免网络重复请求。

确保所有的网络请求只有一个OkHttpClient实例,可以用单例模式。也可以如下:

1
public static OkHttpClient okHttpClient = new OkHttpClient();

okhttp发送请求,封装的方法,必须在子线程运行。另外回调方法是在子线程中,要更新UI必须在主线程,自己处理。下面的方法中的OkHttpClient实例统一用上面生成的。

三,okhttp发送get请求

演示基本的用法,不懂的地方可以github下载源码研究。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//OKHTTP GET
public static String get(String url){
Request request = new Request.Builder().url(url).build();
Response response = null;
try {
response = new OkHttpClient().newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
} catch (IOException e) {
e.printStackTrace();
}
return "";
}

四,OKHttp构建RequestBody

发送post的请求,比较普遍。无论有一个参数,多个参数,或者文件上传,都可以构建特定的RequestBody发送请求。

1.发送一个键值对。

1
RequestBody requestBody = RequestBody.create(MediaType.parse("UTF-8"),"param=value");

2.发送多个参数,构建表单一样的请求参数。

1
2
3
4
RequestBody requestBody = new FormBody.Builder()
.add("param1", "value1")
.add("param12", "value2")
.build();

3. post json字符串

1
2
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(JSON, json);

4. 文件上传

MediaType,文件类型标示,通常”application/octet-stream”就可以,比如jpg图片,可以MediaType.parse(“image/jpg”)。表单参数根据项目需要自行调整。

1
2
3
4
final MediaType mediaType = MediaType.parse("application/octet-stream");
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MediaType.parse("multipart/form-data"));
builder.addFormDataPart("name", fileName);
builder.addFormDataPart("file", fileName, RequestBody.create(mediaType, uploadFile));

五,发送的post请求的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
//使用Request的post方法来提交请求体RequestBody
public static String post(String url, RequestBody requestBody) throws IOException {
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Response response = okHttpClient.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}

六,总结

okhttp是目前比较流行的网络框架,开源项目,本文介绍了本人一些常用的用法,不到之处望留言指出。对比了一些网络框架,还是挺赞的。
有时间再研究研究源码,未完待续,欢迎交流,杜乾,Dusan,Q 291902259。
真实案例,加入登陆,返回的json数据如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{"status":1,"msg":"\u83b7\u53d6\u7528\u6237\u6210\u529f","data":{"uid":"1","username":"zhiwei","nickname":"\u738b\u5fd7\u4f1f","sex":"1","phone":"13315211535","avatar":"http:\/\/gehua.sexhelp.cn\/Uploads\/2016-04-18\/5714ee067a0fb.png","job_number":"181818"}}
private static final String TAG = DuQianTest.class.getSimpleName();
```
``` java
public static void testLogin() {
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("device_mark", "869085024277783")
.add("uid", "1")
.build();
Request request = new Request.Builder()
.url("http://gehua.sexhelp.cn/AppInterface/User/getUserInfoInterface.html")
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
LogUtils.debug(TAG,"error= "+e.toString());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
boolean successful = response.isSuccessful();
if (successful) {
final String result = response.body().string();//注意不是toString
//GsonUtil.json2bean(result, UserInfo.class);//json 2 bean
LogUtils.debug(TAG,"result= "+result);
}
}
});
}

unicode解码(unicode编码转中文)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* unicode解码(unicode编码转中文)
* @param theString
* @return
*/
public static String unicodeDecode(String theString) {
char aChar;
int len = theString.length();
StringBuffer outBuffer = new StringBuffer(len);
for (int x = 0; x < len;) {
aChar = theString.charAt(x++);
if (aChar == '\\') {
aChar = theString.charAt(x++);
if (aChar == 'u') {
// Read the xxxx
int value = 0;
for (int i = 0; i < 4; i++) {
aChar = theString.charAt(x++);
switch (aChar) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value = (value << 4) + aChar - '0';
break;
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
value = (value << 4) + 10 + aChar - 'a';
break;
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
value = (value << 4) + 10 + aChar - 'A';
break;
default:
throw new IllegalArgumentException(
"Malformed \\uxxxx encoding.");
}
}
outBuffer.append((char) value);
} else {
if (aChar == 't')
aChar = '\t';
else if (aChar == 'r')
aChar = '\r';
else if (aChar == 'n')
aChar = '\n';
else if (aChar == 'f')
aChar = '\f';
outBuffer.append(aChar);
}
} else
outBuffer.append(aChar);
}
return outBuffer.toString();
}