okhttp的基础教程(磨砺营马剑威Android)

这篇文章主要总结Android著名网络框架-okhttp的基础使用。

okhttp是什么

okhttp是Android端的一个Http客户端,其基础功能相当于Android自带的HttpURLConnection和Apache HTTP Client,但他却比自带的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基础使用

这里我们主要介绍简单的使用,介绍内容如下

1.get请求

2.post请求,参数是键值对

3.post请求,多种类型的body

4.文件下载

5.加入Gson

get请求

get请求分为同步get和异步get,两者的区别主要get的方式是工作在另一个线程还是工作在本线程。请求的方式大同小异。

首先定义一个OkHttpClient对象,如下

privateOkHttpClient client

=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.

Headers headers = 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=" OTI DSP COR IVA OUR IND COM "

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(Call

call, IOException e){

}

@Override

publicvoidonResponse(Call

call, Response response)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{

privateOkHttpClient

okHttpClient =newOkHttpClient();

publicTextView show;

publicHandler handler =newHandler();

@Override

protectedvoidonCreate(Bundle

savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

show = (TextView) findViewById(R.id.show);

show.setMovementMethod(ScrollingMovementMethod.getInstance());

Request request =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(Call call, IOException e){

}

@Override

publicvoidonResponse(Call call,finalResponse response)throwsIOException{

finalHeaders headers = response.headers();

finalString str =response.body().string();

handler.post(newRunnable() {

@Override

publicvoidrun(){

for(inti =0; 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.Builder builder =newFormBody.Builder();

for(inti =0; i < key.size() ;i ++){

builder.add(key.get(i),value.get(i));

}

RequestBody body = builder.build();

builder中add的是要加入的参数键值对。得到要构造的body后用

Request request =newRequest.Builder().url(url).post(body).build();

获得请求的request,后面的操作就和get方法是一样的,这里可以参考异步get的栗子,构建一个post的request.下面的写法原封不变。

post请求--多种类型的body

上文已经说了post和get的用法主要在构建不同的request上面,所以接下来我们主要讨论的也是如何构建request.

参考上面,我们首先要创建一个requestBody,我们可以用下面的方式去构建,当然这也是okhttp3的方法

MultipartBody.Builder builder =newMultipartBody.Builder().setType(MultipartBody.FORM);

已表单上传的形式去提交post。我们看一下builder的方法

/** Add a part to the body. */

publicBuilderaddPart(RequestBody body){

returnaddPart(Part.create(body));

}

/** Add a part to the body. */

publicBuilderaddPart(Headers headers, RequestBody body){

returnaddPart(Part.create(headers, body));

}

/** Add a form data part to the body. */

publicBuilderaddFormDataPart(String name, Stringvalue){

returnaddPart(Part.createFormData(name,value));

}

/** Add a form data part to the body. */

publicBuilderaddFormDataPart(String name, String filename, RequestBody body){

returnaddPart(Part.createFormData(name, filename, body));

}

从这里我们可以看出可以直接用public Builder addFormDataPart(String name, String filename,

RequestBody body)上传一个File,最后一个参数是请求的实体,可以通过RequestBody.create(final MediaType contentType, final File

file)获得,而MediaType则可以通过下面方法获得

//调用judgeType方法

privatestaticfinal MediaType

MEDIA_TYPE = MediaType.parse(judgeType(fileName);

//judge方法如下

privateStringjudgeType(Stringpath) {

FileNameMap fileNameMap = URLConnection.getFileNameMap();

StringcontentTypeFor = fileNameMap.getContentTypeFor(path);

if(contentTypeFor ==null) {

contentTypeFor ="application/octet-stream";

}

returncontentTypeFor;

}

由于我后台能力比较渣,这里用一个官网的例子来实现一遍我刚才讨论的方法。

MultipartBody.Builder builder =newMultipartBody.Builder()

.setType(MultipartBody.FORM)

.addFormDataPart("image","logo-square.png",

RequestBody.create(MEDIA_TYPE_PNG,newFile("website/static/logo-square.png")));

RequestBody requestBody = builder.build();

Request request =newRequest.Builder()

.header("Authorization","Client-ID

"+"9199fdef135c122")

.url("https://api.imgur.com/3/image")

.post(requestBody)

.build();

当然除了这个方法以外,调用如下方法也是可以的,我们可以利用name和filename自己构造Header传上去。

publicBuilderaddPart(Headers headers, RequestBody body){

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(finalString url,finalString destFileDir,finalResultCallback callback){

finalRequest request =newRequest.Builder().url(url).build();

finalCall call = okHttpClient.newCall(request);

call.enqueue(newCallback() {

@Override

publicvoidonFailure(Call call, IOException e){

}

@Override

publicvoidonResponse(Call call, Response response)throwsIOException{

InputStream is =null;

byte[] buf =newbyte[2048];

intlen =0;

FileOutputStream fos =null;

try{

is =response.body().byteStream();

File file =newFile(destFileDir,getFileName(url));

fos =newFileOutputStream(file);

while((len = is.read(buf)) != -1){

fos.write(buf,0,len);

}

fos.flush();

//....省略后续对已经保存的文件的操作

}catch(IOException e) {

e.printStackTrace();

}finally{

try{

if(is !=null) is.close();

}catch(IOException e) {

}

try

{

if(fos !=null) fos.close();

}catch(IOException e)

{

}

}

}

});

}

加入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;

privateString intro;

privateString shopName;

privateString message;

publicintgetStatus(){

returnstatus;

}

publicvoidsetStatus(intstatus){

this.status = status;

}

publicStringgetIntro(){

returnintro;

}

publicvoidsetIntro(String

intro){

this.intro = intro;

}

publicStringgetShopName(){

returnshopName;

}

publicvoidsetShopName(String

shopName){

this.shopName = shopName;

}

publicStringgetMessage(){

returnmessage;

}

publicvoidsetMessage(String

message){

this.message = message;

}

}

在获得到response之后,用如下代码把Json文件解析成result对象。然后调用result对象的get方法就可以得到json文件中的intro的值和shopname的值,以及status和message.这里就不多介绍了

Test result =newGson().fromJson(response.body().string,Test.class);

本文简单介绍了okhttp的使用,更多内容关注微信公众号mjw-java或访问www.moliying.com

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容