android okhttp的基础使用【入门推荐】
这篇文章主要总结Android著名网络框架-okhttp的基础使用,后续可能会有关于他的高级使用。
okhttp是什么
okhttp是Android端的一个Http客户端,其基础功能相当于Android自带的HttpURLConnection和ApacheHTTPClient,但他却比自带的2个Http客户端优越很多,一者是写法简单,二者okhttp处理很多网络复杂问题,如会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败等等很多问题。关于第二者,这篇文章不讨论。
okhttp的导入
Gradle导入
compile'com.squareup.okhttp3:okhttp:3.2.0' compile'com.squareup.okio:okio:1.6.0'
okhttp基础使用
这里我们主要介绍简单的使用,介绍内容如下
- get请求
- post请求,参数是键值对
- post请求,多种类型的body
- 文件下载
- 加入Gson
get请求
get请求分为同步get和异步get,两者的区别主要get的方式是工作在另一个线程还是工作在本线程。请求的方式大同小异。
首先定义一个OkHttpClient对象,如下
privateOkHttpClientclient=newOkHttpClient();
然后构建一个Request,构建方式如下:
Requestrequest=newRequest.Builder().
url("http://www.baidu.com").
build();
这个是最简单的request的构建方式,当然我们可以构建的很复杂。
Requestrequest=newRequest.Builder().
url("http://www.baidu.com").
addHeader("User-Agent","android").
header("Content-Type","text/html;charset=utf-8").
build();
通过addHeader和header方法为请求增加请求头部,注意使用header(name,value)可以设置唯一的name、value。如果已经有值,旧的将被移除,然后添加新的。使用addHeader(name,value)可以添加多值(添加,不移除已有的)。
同步的get方法,通过client.newCall(request).execute()方法得到请求的response.
Responseresponse=okHttpClient.newCall(request).execute();
OkHttp封装了很多处理response的方法,比如response.headers()的得到headers.
Headersheaders=response.headers();
for(inti=0;i<headers.size();i++){
System.out.println(headers.name(i)+":"+headers.value(i));}
结果如下:
Date:Mon,18Apr201605:23:43GMT Content-Type:text/html;charset=utf-8 Transfer-Encoding:chunked Connection:Keep-Alive Vary:Accept-Encoding Set-Cookie:BAIDUID=A323EC9BF678C0EB78E20741FD71211B:FG=1;expires=Thu,31-Dec-3723:55:55GMT;max-age=2147483647;path=/;domain=.baidu.com Set-Cookie:BIDUPSID=A323EC9BF678C0EB78E20741FD71211B;expires=Thu,31-Dec-3723:55:55GMT;max-age=2147483647;path=/;domain=.baidu.com Set-Cookie:PSTM=1460957023;expires=Thu,31-Dec-3723:55:55GMT;max-age=2147483647;path=/;domain=.baidu.com Set-Cookie:BDSVRTM=0;path=/ Set-Cookie:BD_HOME=0;path=/ Set-Cookie:H_PS_PSSID=1434_19672_18281_19690_17948_18205_19558_15952_12257;path=/;domain=.baidu.com P3P:CP="OTIDSPCORIVAOURINDCOM" Cache-Control:private Cxy_all:baidu+2db7793e0e32b9f6c20be8f623e1ae43 Expires:Mon,18Apr201605:22:55GMT X-Powered-By:HPHP Server:BWS/1.1 X-UA-Compatible:IE=Edge,chrome=1 BDPAGETYPE:1 BDQID:0xfacc6fc10004ca96 BDUSERID:0 OkHttp-Sent-Millis:1460957021226 OkHttp-Received-Millis:1460957021430
响应报文的实体可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()。
异步的get请求得到的response方法是通过如下方法
okHttpClient.newCall(request).enqueue(newCallback(){
@Override
publicvoidonFailure(Callcall,IOExceptione){
}
@Override
publicvoidonResponse(Callcall,Responseresponse)throwsIOException{
}
});
在onResponse方法中,执行请求成功的代码,onFailure方法中,执行请求失败的代码,下面给一个完整的异步get的栗子
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.support.v7.app.AppCompatActivity;
importandroid.text.method.ScrollingMovementMethod;
importandroid.widget.TextView;
importjava.io.IOException;
importokhttp3.Call;
importokhttp3.Callback;
importokhttp3.Headers;
importokhttp3.OkHttpClient;
importokhttp3.Request;
importokhttp3.Response;
publicclassMainActivityextendsAppCompatActivity{
privateOkHttpClientokHttpClient=newOkHttpClient();
publicTextViewshow;
publicHandlerhandler=newHandler();
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show=(TextView)findViewById(R.id.show);
show.setMovementMethod(ScrollingMovementMethod.getInstance());
Requestrequest=newRequest.Builder().
url("http://www.baidu.com").
addHeader("User-Agent","android").
header("Content-Type","text/html;charset=utf-8").
get().
build();
okHttpClient.newCall(request).enqueue(newCallback(){
@Override
publicvoidonFailure(Callcall,IOExceptione){
}
@Override
publicvoidonResponse(Callcall,finalResponseresponse)throwsIOException{
finalHeadersheaders=response.headers();
finalStringstr=response.body().string();
handler.post(newRunnable(){
@Override
publicvoidrun(){
for(inti=0;i<headers.size();i++){
show.append(headers.name(i)+":"+headers.value(i));
show.append(str);
}
}
});
}
});
}
}
其实按照官网说的,回调是发生在response的headers准备好就发生的,所以有时候请求response的实体部分会发生阻塞。
post请求——键值对为参数。
post请求和get请求除了在构建request上面不同以外,在处理response上面都是一样的,所以下面我们只讨论一下post构建request,当然post也是支持同步post和异步post的,可以参考get方法。
在构建post的request时候,首先用FormBody.Builder去构建request的body部分,栗子如下,当然这是OKHttp3的方法.
FormBody.Builderbuilder=newFormBody.Builder();
for(inti=0;i<key.size();i++){
builder.add(key.get(i),value.get(i));
}
RequestBodybody=builder.build();
builder中add的是要加入的参数键值对。得到要构造的body后用
Requestrequest=newRequest.Builder().url(url).post(body).build();
获得请求的request,后面的操作就和get方法是一样的,这里可以参考异步get的栗子,构建一个post的request.下面的写法原封不变。
post请求--多种类型的body
上文已经说了post和get的用法主要在构建不同的request上面,所以接下来我们主要讨论的也是如何构建request.
参考上面,我们首先要创建一个requestBody,我们可以用下面的方式去构建,当然这也是okhttp3的方法
MultipartBody.Builderbuilder=newMultipartBody.Builder().setType(MultipartBody.FORM);
已表单上传的形式去提交post。我们看一下builder的方法
/**Addaparttothebody.*/
publicBuilderaddPart(RequestBodybody){
returnaddPart(Part.create(body));
}
/**Addaparttothebody.*/
publicBuilderaddPart(Headersheaders,RequestBodybody){
returnaddPart(Part.create(headers,body));
}
/**Addaformdataparttothebody.*/
publicBuilderaddFormDataPart(Stringname,Stringvalue){
returnaddPart(Part.createFormData(name,value));
}
/**Addaformdataparttothebody.*/
publicBuilderaddFormDataPart(Stringname,Stringfilename,RequestBodybody){
returnaddPart(Part.createFormData(name,filename,body));
}
从这里我们可以看出可以直接用publicBuilderaddFormDataPart(Stringname,Stringfilename,RequestBodybody)上传一个File,最后一个参数是请求的实体,可以通过RequestBody.create(finalMediaTypecontentType,finalFilefile)获得,而MediaType则可以通过下面方法获得
//调用judgeType方法
privatestaticfinalMediaTypeMEDIA_TYPE=MediaType.parse(judgeType(fileName);
//judge方法如下
privateStringjudgeType(Stringpath){
FileNameMapfileNameMap=URLConnection.getFileNameMap();
StringcontentTypeFor=fileNameMap.getContentTypeFor(path);
if(contentTypeFor==null){
contentTypeFor="application/octet-stream";
}
returncontentTypeFor;
}
由于我后台能力比较渣,这里用一个官网的例子来实现一遍我刚才讨论的方法。
MultipartBody.Builderbuilder=newMultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("image","logo-square.png",
RequestBody.create(MEDIA_TYPE_PNG,newFile("website/static/logo-square.png")));
RequestBodyrequestBody=builder.build();
Requestrequest=newRequest.Builder()
.header("Authorization","Client-ID"+"9199fdef135c122")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
当然除了这个方法以外,调用如下方法也是可以的,我们可以利用name和filename自己构造Header传上去。
publicBuilderaddPart(Headersheaders,RequestBodybody){
returnaddPart(Part.create(headers,body))
栗子如下:
builder.addPart(Headers.of("Content-Disposition","form-data;name=\""+name+"\";filename=\""+fileName+"\""),fileBody);
后面的写法和上面类似,这样我们就实现了文件上传的写法。
文件下载
刚才我们上面已经说了,希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()。换句话说,文件的下载可以简单的通过get请求,得到相应的response,在把他的实体转换成二进制流写入文件,就是实现了文件的下载。主要的写法就是文件的读写,跟OKHttp关系不大,当然我们也可以用okio来实现文件的读写,这里水平有限就不介绍了。下面给一个简单的例子。
privatevoid_download(finalStringurl,finalStringdestFileDir,finalResultCallbackcallback){
finalRequestrequest=newRequest.Builder().url(url).build();
finalCallcall=okHttpClient.newCall(request);
call.enqueue(newCallback(){
@Override
publicvoidonFailure(Callcall,IOExceptione){
}
@Override
publicvoidonResponse(Callcall,Responseresponse)throwsIOException{
InputStreamis=null;
byte[]buf=newbyte[2048];
intlen=0;
FileOutputStreamfos=null;
try{
is=response.body().byteStream();
Filefile=newFile(destFileDir,getFileName(url));
fos=newFileOutputStream(file);
while((len=is.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.flush();
//....省略后续对已经保存的文件的操作
}catch(IOExceptione){
e.printStackTrace();
}finally{
try{
if(is!=null)is.close();
}catch(IOExceptione){
}
try
{
if(fos!=null)fos.close();
}catch(IOExceptione)
{
}
}
}
});
}
加入Gson
接下来,我们讨论一个很实际的问题,Android的网络请求一般不会去请求一个网站的Html,更多的是请求后台接口的Json文件,所以我们用Gson来处理json的解析。这一部分和前面就不同了,前面多数讲的是如何构建不同的request来得到response,而对响应的结果,处理都是一致的。但这里主要的写法就是用Gson去处理response,而request的构建则根据上面介绍的方法去构建,无需改变。
Gson的导入
compile'com.google.code.gson:gson:2.6.2'
比如我们后台给出的api是这样一个json文件
{
"status":0,
"intro":"你好",
"shopName":"byhieg",
"message":"查询成功",
}
则我们可以简单的构建这样的一个Test.java文件,如下所示:
publicclassTest{
/**
*status:0
*intro:byhieg
*shopName:byhige
*message:查询成功
*/
privateintstatus;
privateStringintro;
privateStringshopName;
privateStringmessage;
publicintgetStatus(){
returnstatus;
}
publicvoidsetStatus(intstatus){
this.status=status;
}
publicStringgetIntro(){
returnintro;
}
publicvoidsetIntro(Stringintro){
this.intro=intro;
}
publicStringgetShopName(){
returnshopName;
}
publicvoidsetShopName(StringshopName){
this.shopName=shopName;
}
publicStringgetMessage(){
returnmessage;
}
publicvoidsetMessage(Stringmessage){
this.message=message;
}
}
在获得到response之后,用如下代码把Json文件解析成result对象。然后调用result对象的get方法就可以得到json文件中的intro的值和shopname的值,以及status和message.这里就不多介绍了
Testresult=newGson().fromJson(response.body().string,Test.class);
总结
简单介绍了okHttp的使用,对于一些高级用法请关注下篇文章,本人水平有限,如有错误,还望指正。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!