早在毕业那段期间,群里有很多小伙伴在问关于okhttp的问题,当时因为不了解。所以没有回答的上。记得十月份有次面试,一个面试官问我关于网络请求的东西时,我记得当时我是说。我是通过HttpClient封装了一个网络请求的工具类。当然,或许他想问的是我关于okhttp有没有了解把。谷歌在6.0中删除了关于httpclient的API。(其实我有httpclient源码)。于是乎,为了了解下,最近还是学习了下。
简单说下学习okhttp的理由
google在Android 6.0中删除了关于Httpclient的APi,采用的则是okhttp高效的使用http,使应用运行更快,更省流量响应缓存数据,避免重复网络请求无缝的支持GZIP从而来减少流量的使用使用简单方便,请求和响应的APi具有流畅的建造和不变性。同时支持同步异步调用回调函数如果网络出现问题,他会从常见的连接问题中恢复如果服务器配置多个URL,当第一个连接失败时,它会尝试链接下一个
配置环境
github地址:http://github.com/square/okhttp
在build.gradle添加:
compile
'com.squareup.okhttp:okhttp:2.7.5'
compile
'com.squareup.okio:okio:1.11.0'
jar下载地址:
Okhttp OKio
基本使用教程
1) OkHttpClient:新建一个OkHttpClient实例,用于处理请求。
2) Request:构建请求参数,如url,请求方式,请求参数,header等。
3) Call:生成一个具体请求实例,相当于将请求封装成了任务;两种方式:
①、call.execute(),非异步方式,会阻塞线程,等待返回结果。
②、call.enqueue(Callback),异步方式。
4) Response:结果响应
HttpGet
同步http请求
private OkHttpClient okHttpClient =
new OkHttpClient();
private Response response;
okHttpClient.setConnectTimeout(
15, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(
15, TimeUnit.SECONDS);
okHttpClient.setWriteTimeout(
15, TimeUnit.SECONDS);
Request request =
new Request.Builder().url(url).
get().build();
try {
response = okHttpClient.newCall(
request).
execute();
if (
response.isSuccessful()) {
Log.i(TAG,
" onResponse() reuslt=" +
response.body().
string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
异步http请求
private OkHttpClient okHttpClient =
new OkHttpClient();
private Response response;
okHttpClient.setConnectTimeout(
15, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(
15, TimeUnit.SECONDS);
okHttpClient.setWriteTimeout(
15, TimeUnit.SECONDS);
Request request =
new Request.Builder().url(url).
get().build();
okHttpClient.newCall(
request).enqueue(
new Callback() {
public void onFailure(
Call call, IOException e) {
Log.e(TAG,
"onFailure() e=" + e);
}
public void onResponse(
Call call, final
Response response) throws IOException {
Log.i(TAG,
" onResponse() reuslt=" +
response.body().
string());
}
});
HttpPost
看了上面的简单的get请求,基本上整个的用法也就掌握了。post和get的用法差不多。
同步的Post请求
okHttpClient
.setConnectTimeout(
15, TimeUnit
.SECONDS)
okHttpClient
.setReadTimeout(
15, TimeUnit
.SECONDS)
okHttpClient
.setWriteTimeout(
15, TimeUnit
.SECONDS)
RequestBody body=new FormEncodingBuilder()
.add(
"name",
"马云飞")
.build()
Request request = new Request
.Builder()
.url(url)
.post(body)
.build()
try {
response = okHttpClient
.newCall(request)
.execute()
if (response
.isSuccessful()) {
Log
.i(TAG,
" onResponse() reuslt=" + response
.body()
.string())
}
} catch (IOException e) {
e
.printStackTrace()
}
}
异步的Post请求
okHttpClient
.setConnectTimeout(
15, TimeUnit
.SECONDS)
okHttpClient
.setReadTimeout(
15, TimeUnit
.SECONDS)
okHttpClient
.setWriteTimeout(
15, TimeUnit
.SECONDS)
RequestBody body=new FormEncodingBuilder()
.add(
"name",
"马云飞")
.build()
Request request = new Request
.Builder()
.url(url)
.post(body)
.build()
okHttpClient
.newCall(request)
.enqueue(new Callback() {
public void onFailure(
Call call, IOException e) {
Log
.e(TAG,
"onFailure() e=" + e)
}
public void onResponse(
Call call, final Response response) throws IOException {
Log
.i(TAG,
" onResponse() reuslt=" + response
.body()
.string())
}
})
此时,基本的get与post就这么介绍完了。那么用到网络请求除了get和post还有什么呢?对了,就是文件的上传与下载。针对群里一些小伙伴需要得到当前的进度,所以下面会上整体的代码,我会在放完代码后做出解释。
文件上传
public String uploadFile(
String uploadUrl, File file) {
if (httpUtils.isConnnected()) {
RequestBody filebody = createProgressRequestBody(MEDIA_OBJECT_STREAM, file);
RequestBody body =
new MultipartBuilder().type(MultipartBuilder.FORM).addFormDataPart(file.getName(), file.getName(), filebody).build();
Request request =
new Request.Builder()
.url(uploadUrl)
.post(body)
.build();
Response response =
null;
try {
response = okHttpClient.newCall(
request).
execute();
return
response.body().
string();
} catch (IOException e) {
}
}
return
null;
}
public RequestBody
createProgressRequestBody(
final MediaType contentType,
final File file) {
return new RequestBody() {
public MediaType
contentType() {
return contentType;
}
public long contentLength() {
return file.length();
}
public void writeTo(BufferedSink sink)
throws IOException {
Source source;
try {
source = Okio.source(file);
Buffer buf =
new Buffer();
long total = contentLength();
long current =
0;
for (
long readCount; (readCount = source.read(buf,
2048)) != -
1; ) {
sink.write(buf, readCount);
current += readCount;
if (onProgressStateListener !=
null) {
onProgressStateListener.upload(byteUtils.getSize(current), byteUtils.getSize(total), byteUtils.getByte(current), byteUtils.getByte(total));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
};
}
此时你们会看到我判断了onProgressStateListener此接口不为空的情况,其实就是如果不需要得到当前的进度,我们就无需实现此接口。如果不需要得到进度,你也可以把上面createProgressRequestBody方法换成这句话:
filebody=RequestBody.
create(MEDIA_OBJECT_STREAM,file);
文件下载
Request request =
new Request.Builder().url(httpDownloadBean.getUrl()).build();
okHttpClient.newCall(
request).enqueue(
new Callback() {
public void onResponse(
Response response) {
InputStream inputStream =
null;
try {
download_total =
response.body().contentLength();
inputStream =
response.body().byteStream();
if (
response.isSuccessful()) {
writeSDFromInput(httpDownloadBean.getStoragepath(), httpDownloadBean.getFilepath(), inputStream);
}
else {
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void onFailure(
Request arg0, IOException arg1) {
}
});
这里我们需要把inputstream写入sd卡:
public File
writeSDFromInput(String path, String fileName, InputStream input) {
File file =
null;
OutputStream output =
null;
try {
fileSupport.createSDDir(path);
file = fileSupport.createSDFile(path + fileName);
output =
new FileOutputStream(file);
byte buffer[] =
new byte[
1024];
int length =
0;
long current =
0;
while ((length = input.read(buffer)) != -
1) {
current += length;
if (onProgressStateListener !=
null) {
onProgressStateListener.download(byteUtils.getSize(current), byteUtils.getSize(download_total), byteUtils.getByte(current), byteUtils.getByte(download_total));
}
output.write(buffer,
0, length);
}
output.flush();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
output.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
return file;
}
这里也和上传是一样的,你需要得到进度的时候实现此接口。
总结
Okhttp默认的配置为我们提供了非常重要实用功能。通过采用上述步骤,你可以增加它的灵活性和内省的能力并提高应用程序的质量。我对比过我用Httpclient和Okhttp的写的工具类,如果不需要得到进度的话,代码量差了一倍之多。从此而知,okhttp的确很好用。