本篇记录的是Android开发中OkHttp框架的使用,下面介绍OkHttp库的用法,本篇会给出OkHttp的使用demo,demo中包含了常用的get请求、post请求、文件的上传和下载,demo运行的效果如下图所示:
下面上代码一一说明:
要使用OkHttp,必须在项目中先导入OkHttp,在app模块的build.gradle文件中,加入下面的代码:
1
2
3
4
5
6
|
dependencies {
compile fileTree(dir:
'libs'
, include: [
'*.jar'
])
testCompile
'junit:junit:4.12'
compile
'com.android.support:appcompat-v7:23.1.1'
compile
'com.squareup.okhttp3:okhttp:3.2.0'
}
|
(1)GET请求
最简单的GET请求用法如下:
1
2
3
4
5
6
7
8
|
//简单的Get请求,不带参数
public
void
simpleGetClick(View view) {
okHttpClient =
new
OkHttpClient();
Request request =
new
Request.Builder()
.build();
okHttpClient.newCall(request).enqueue(callback);
}
|
1
2
3
4
5
6
7
8
9
|
//带参数的Get请求
public
void
addParamGetClick(View view) {
okHttpClient =
new
OkHttpClient();
Request request =
new
Request.Builder()
.addHeader(
"token"
,
"asdlfjkasdljfaskdjfalsjkljalk"
)
//请求头中加入参数
.url(
"http://192.168.1.170:8088/okhttp/test_param_get.php?username=zhangsan&phone=13888888888"
) //携带参数
.build();
okHttpClient.newCall(request).enqueue(callback);
}
|
需要注意的是,上面的代码中,callback是请求后的回调接口,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
//请求后的回调接口
private
Callback callback =
new
Callback() {
@Override
public
void
onFailure(Call call, IOException e) {
setResult(e.getMessage(),
false
);
}
@Override
public
void
onResponse(Call call, Response response)
throws
IOException {
setResult(response.body().string(),
true
);
}
};
|
(2)POST请求
比较简单的POST请求,用法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//简单的带参数和Header的post请求
public
void
simplePostClick(View view) {
okHttpClient =
new
OkHttpClient();
RequestBody requestBody =
new
FormBody.Builder()
.add(
"username"
,
"wangwu"
)
.add(
"password"
,
"hello12345"
)
.add(
"gender"
,
"female"
)
.build();
Request request =
new
Request.Builder()
.post(requestBody)
.addHeader(
"token"
,
"helloworldhelloworldhelloworld"
)
.build();
okHttpClient.newCall(request).enqueue(callback);
}
|
如果我们的POST请求稍微复杂点,比如携带的参数既有文本类型的,又有文件类型的,那么可以用下面的方式来请求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//带文本参数和文件参数的post请求
public
void
filePostClick(View view) {
RequestBody fileBody = RequestBody.create(MediaType.parse(
"text/plain; charset=utf-8"
), tempFile);
RequestBody requestBody =
new
MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"username"
,
"wangwu"
)
.addFormDataPart(
"password"
,
"hello12345"
)
.addFormDataPart(
"gender"
,
"female"
)
.addFormDataPart(
"file"
,
"info.txt"
, fileBody)
.build();
Request request =
new
Request.Builder()
.post(requestBody)
.addHeader(
"token"
,
"helloworldhelloworldhelloworld"
)
.build();
okHttpClient.newCall(request).enqueue(callback);
}
|
(3)文件的上传
文件上传并显示进度,这个代码稍微有些复杂,下面直接上代码:
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
package
com.test.testokhttp;
import
android.os.Environment;
import
android.support.v7.app.AppCompatActivity;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.ProgressBar;
import
android.widget.TextView;
import
android.widget.Toast;
import
java.io.File;
import
java.io.IOException;
import
java.util.concurrent.TimeUnit;
import
okhttp3.Call;
import
okhttp3.Callback;
import
okhttp3.Interceptor;
import
okhttp3.MediaType;
import
okhttp3.MultipartBody;
import
okhttp3.OkHttpClient;
import
okhttp3.Request;
import
okhttp3.RequestBody;
import
okhttp3.Response;
import
okhttp3.ResponseBody;
import
okio.Buffer;
import
okio.BufferedSink;
import
okio.BufferedSource;
import
okio.ForwardingSink;
import
okio.ForwardingSource;
import
okio.Okio;
import
okio.Sink;
import
okio.Source;
public
class
UploadActivity
extends
AppCompatActivity {
private
OkHttpClient okHttpClient;
private
TextView resultTextView;
private
ProgressBar progressBar;
private
File tempFile;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload);
setTitle(
"上传文件并显示进度"
);
resultTextView = (TextView) findViewById(R.id.result_textview);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setMax(
100
);
okHttpClient =
new
OkHttpClient.Builder()
.readTimeout(
30
, TimeUnit.SECONDS)
.connectTimeout(
10
, TimeUnit.SECONDS)
.writeTimeout(
60
, TimeUnit.SECONDS)
.build();
}
//点击按钮开始上传文件
public
void
startUploadClick(View view) {
tempFile =
new
File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +
"test.pdf"
);
RequestBody requestBody =
new
MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file"
,
"test.pdf"
, RequestBody.create(MediaType.parse(
"application/pdf; charset=utf-8"
), tempFile))
.build();
ProgressRequestBody progressRequestBody =
new
ProgressRequestBody(requestBody, progressListener);
Request request =
new
Request.Builder()
.post(progressRequestBody)
.build();
okHttpClient.newCall(request).enqueue(callback);
}
//通过实现进度回调接口中的方法,来显示进度
private
ProgressListener progressListener =
new
ProgressListener() {
@Override
public
void
update(
long
bytesRead,
long
contentLength,
boolean
done) {
int
progress = (
int
) (
100.0
* bytesRead / contentLength);
progressBar.setProgress(progress);
}
};
//请求后的回调方法
private
Callback callback =
new
Callback() {
@Override
public
void
onFailure(Call call, IOException e) {
setResult(e.getMessage(),
false
);
}
@Override
public
void
onResponse(Call call, Response response)
throws
IOException {
setResult(response.body().string(),
true
);
}
};
//显示请求返回的结果
private
void
setResult(
final
String msg,
final
boolean
success) {
runOnUiThread(
new
Runnable() {
@Override
public
void
run() {
if
(success) {
Toast.makeText(UploadActivity.
this
,
"请求成功"
, Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(UploadActivity.
this
,
"请求失败"
, Toast.LENGTH_SHORT).show();
}
resultTextView.setText(msg);
}
});
}
//自定义的RequestBody,能够显示进度
public
class
ProgressRequestBody
extends
RequestBody {
//实际的待包装请求体
private
final
RequestBody requestBody;
//进度回调接口
private
final
ProgressListener progressListener;
//包装完成的BufferedSink
private
BufferedSink bufferedSink;
/**
* 构造函数,赋值
*
* @param requestBody 待包装的请求体
* @param progressListener 回调接口
*/
public
ProgressRequestBody(RequestBody requestBody, ProgressListener progressListener) {
this
.requestBody = requestBody;
this
.progressListener = progressListener;
}
/**
* 重写调用实际的响应体的contentType
*
* @return MediaType
*/
@Override
public
MediaType contentType() {
return
requestBody.contentType();
}
/**
* 重写调用实际的响应体的contentLength
*
* @return contentLength
* @throws IOException 异常
*/
@Override
public
long
contentLength()
throws
IOException {
return
requestBody.contentLength();
}
/**
* 重写进行写入
*
* @param sink BufferedSink
* @throws IOException 异常
*/
@Override
public
void
writeTo(BufferedSink sink)
throws
IOException {
if
(bufferedSink ==
null
) {
//包装
bufferedSink = Okio.buffer(sink(sink));
}
//写入
requestBody.writeTo(bufferedSink);
//必须调用flush,否则最后一部分数据可能不会被写入
bufferedSink.flush();
}
/**
* 写入,回调进度接口
*
* @param sink Sink
* @return Sink
*/
private
Sink sink(Sink sink) {
return
new
ForwardingSink(sink) {
//当前写入字节数
long
bytesWritten = 0L;
//总字节长度,避免多次调用contentLength()方法
long
contentLength = 0L;
@Override
public
void
write(Buffer source,
long
byteCount)
throws
IOException {
super
.write(source, byteCount);
if
(contentLength ==
0
) {
//获得contentLength的值,后续不再调用
contentLength = contentLength();
}
//增加当前写入的字节数
bytesWritten += byteCount;
//回调
progressListener.update(bytesWritten, contentLength, bytesWritten == contentLength);
}
};
}
}
//进度回调接口
interface
ProgressListener {
void
update(
long
bytesRead,
long
contentLength,
boolean
done);
}
}
|
(4)文件的下载
下载和上传类似,区别在于,需要我们实习自定义的ResponseBody而不是RequestBody了,下面上代码:
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
import
android.os.Environment;
import
android.support.v7.app.AppCompatActivity;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.ProgressBar;
import
android.widget.TextView;
import
android.widget.Toast;
import
java.io.File;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.InputStream;
import
java.util.concurrent.TimeUnit;
import
okhttp3.Call;
import
okhttp3.Callback;
import
okhttp3.Interceptor;
import
okhttp3.MediaType;
import
okhttp3.OkHttpClient;
import
okhttp3.Request;
import
okhttp3.Response;
import
okhttp3.ResponseBody;
import
okio.Buffer;
import
okio.BufferedSource;
import
okio.ForwardingSource;
import
okio.Okio;
import
okio.Source;
public
class
DownloadActivity
extends
AppCompatActivity {
private
OkHttpClient okHttpClient;
private
TextView resultTextView;
private
ProgressBar progressBar;
private
File tempFile;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
setTitle(
"下载文件并显示进度"
);
okHttpClient =
new
OkHttpClient.Builder()
.addNetworkInterceptor(
new
Interceptor() {
@Override
public
Response intercept(Interceptor.Chain chain)
throws
IOException {
Response originalResponse = chain.proceed(chain.request());
return
originalResponse.newBuilder()
.body(
new
ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.connectTimeout(
5
, TimeUnit.SECONDS)
.readTimeout(
300
, TimeUnit.SECONDS)
.writeTimeout(
30
, TimeUnit.SECONDS)
.build();
resultTextView = (TextView) findViewById(R.id.result_textview);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
tempFile =
new
File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + System.currentTimeMillis() +
".pdf"
);
}
//下载文件
public
void
startDownloadClick(View view) {
Request request =
new
Request.Builder()
.build();
okHttpClient.newCall(request).enqueue(callback);
}
private
ProgressListener progressListener =
new
ProgressListener() {
@Override
public
void
update(
long
bytesRead,
long
contentLength,
boolean
done) {
int
progress = (
int
) (
100.0
* bytesRead / contentLength);
progressBar.setProgress(progress);
}
};
//请求后的回调方法
private
Callback callback =
new
Callback() {
@Override
public
void
onFailure(Call call, IOException e) {
setResult(e.getMessage(),
false
);
}
@Override
public
void
onResponse(Call call, Response response)
throws
IOException {
if
(response !=
null
) {
//下载完成,保存数据到文件
InputStream is = response.body().byteStream();
FileOutputStream fos =
new
FileOutputStream(tempFile);
byte
[] buf =
new
byte
[
1024
];
int
hasRead =
0
;
while
((hasRead = is.read(buf)) >
0
) {
fos.write(buf,
0
, hasRead);
}
fos.close();
is.close();
setResult(
"下载成功"
,
true
);
}
}
};
//显示请求返回的结果
private
void
setResult(
final
String msg,
final
boolean
success) {
runOnUiThread(
new
Runnable() {
@Override
public
void
run() {
if
(success) {
Toast.makeText(DownloadActivity.
this
,
"请求成功"
, Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(DownloadActivity.
this
,
"请求失败"
, Toast.LENGTH_SHORT).show();
}
resultTextView.setText(msg);
}
});
}
//自定义的ResponseBody,在其中处理进度
private
static
class
ProgressResponseBody
extends
ResponseBody {
private
final
ResponseBody responseBody;
private
final
ProgressListener progressListener;
private
BufferedSource bufferedSource;
public
ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this
.responseBody = responseBody;
this
.progressListener = progressListener;
}
@Override
public
MediaType contentType() {
return
responseBody.contentType();
}
@Override
public
long
contentLength() {
return
responseBody.contentLength();
}
@Override
public
BufferedSource source() {
if
(bufferedSource ==
null
) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return
bufferedSource;
}
private
Source source(Source source) {
return
new
ForwardingSource(source) {
long
totalBytesRead = 0L;
@Override
public
long
read(Buffer sink,
long
byteCount)
throws
IOException {
long
bytesRead =
super
.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -
1
? bytesRead :
0
;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -
1
);
return
bytesRead;
}
};
}
}
//进度回调接口
interface
ProgressListener {
void
update(
long
bytesRead,
long
contentLength,
boolean
done);
}
}
|