当前位置: 移动技术网 > 移动技术>移动开发>Android > android okhttp的基础使用【入门推荐】

android okhttp的基础使用【入门推荐】

2019年07月24日  | 移动技术网移动技术  | 我要评论
这篇文章主要总结android著名网络框架-okhttp的基础使用,后续可能会有关于他的高级使用。 okhttp是什么 okhttp是android端的一个http客户

这篇文章主要总结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对象,如下

private okhttpclient client = new okhttpclient();

然后构建一个request,构建方式如下:

request request = new request.builder().
url("http://www.baidu.com").
build();

这个是最简单的request的构建方式,当然我们可以构建的很复杂。

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

 response response = okhttpclient.newcall(request).execute();

okhttp封装了很多处理response的方法,比如response.headers()的得到headers.

headers headers = response.headers();
 for (int i = 0; i < headers.size(); i++) {
system.out.println(headers.name(i) + ": " + headers.value(i)); }

结果如下:

date: mon, 18 apr 2016 05:23:43 gmt
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-37 23:55:55 gmt; max-age=2147483647; path=/; domain=.baidu.com
set-cookie: bidupsid=a323ec9bf678c0eb78e20741fd71211b; expires=thu, 31-dec-37 23:55:55 gmt; max-age=2147483647; path=/; domain=.baidu.com
set-cookie: pstm=1460957023; expires=thu, 31-dec-37 23:55:55 gmt; 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, 18 apr 2016 05:22:55 gmt
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(new callback() {
      @override
      public void onfailure(call call, ioexception e) {
      }  
      @override
      public void onresponse(call call, response response) throws ioexception {
      }
    });

在onresponse方法中,执行请求成功的代码,onfailure方法中,执行请求失败的代码,下面给一个完整的异步get的栗子

import android.os.bundle;
import android.os.handler;
import android.support.v7.app.appcompatactivity;
import android.text.method.scrollingmovementmethod;
import android.widget.textview;
import java.io.ioexception;
import okhttp3.call;
import okhttp3.callback;
import okhttp3.headers;
import okhttp3.okhttpclient;
import okhttp3.request;
import okhttp3.response;
public class mainactivity extends appcompatactivity {
 private okhttpclient okhttpclient = new okhttpclient();
 public textview show;
 public handler handler = new handler();
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_main);
  show = (textview) findviewbyid(r.id.show);
  show.setmovementmethod(scrollingmovementmethod.getinstance());
  request request = new request.builder().
    url("http://www.baidu.com").
    addheader("user-agent", "android").
    header("content-type", "text/html; charset=utf-8").
    get().
    build();
  okhttpclient.newcall(request).enqueue(new callback() {
   @override
   public void onfailure(call call, ioexception e) {
   }
   @override
   public void onresponse(call call, final response response) throws ioexception {
    final headers headers = response.headers();
    final string str = response.body().string();
    handler.post(new runnable() {
     @override
     public void run() {
      for (int i = 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.builder builder = new formbody.builder();
  for(int i = 0 ; i < key.size() ;i ++){
   builder.add(key.get(i),value.get(i));
  }
  requestbody body = builder.build();

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

request request = new request.builder().url(url).post(body).build();

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

post请求--多种类型的body

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

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

multipartbody.builder builder = new multipartbody.builder().settype(multipartbody.form);

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

 /** add a part to the body. */
 public builder addpart(requestbody body) {
  return addpart(part.create(body));
 }
 /** add a part to the body. */
 public builder addpart(headers headers, requestbody body) {
  return addpart(part.create(headers, body));
 }
 /** add a form data part to the body. */
 public builder addformdatapart(string name, string value) {
  return addpart(part.createformdata(name, value));
 }
 /** add a form data part to the body. */
 public builder addformdatapart(string name, string filename, requestbody body) {
  return addpart(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方法
private static final mediatype media_type = mediatype.parse(judgetype(filename);
//judge方法如下
private string judgetype(string path) {
  filenamemap filenamemap = urlconnection.getfilenamemap();
  string contenttypefor = filenamemap.getcontenttypefor(path);
  if (contenttypefor == null) {
   contenttypefor = "application/octet-stream";
  }
  return contenttypefor;
 }

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

multipartbody.builder builder = new multipartbody.builder()
  .settype(multipartbody.form)
  .addformdatapart("image", "logo-square.png",
   requestbody.create(media_type_png, new file("website/static/logo-square.png")));
requestbody requestbody = builder.build();
 request request = new request.builder()
  .header("authorization", "client-id " +"9199fdef135c122")
  .url("https://api.imgur.com/3/image")
  .post(requestbody)
  .build();

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

public builder addpart(headers headers, requestbody body) {
  return addpart(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来实现文件的读写,这里水平有限就不介绍了。下面给一个简单的例子。

private void _download(final string url, final string destfiledir, final resultcallback callback) {
  final request request = new request.builder().url(url).build();
  final call call = okhttpclient.newcall(request);
  call.enqueue(new callback() {
   @override
   public void onfailure(call call, ioexception e) {

   }
   @override
   public void onresponse(call call, response response) throws ioexception {
    inputstream is = null;
    byte[] buf = new byte[2048];
    int len = 0;
    fileoutputstream fos = null;
    try {
     is = response.body().bytestream();
     file file = new file(destfiledir, getfilename(url));
     fos = new fileoutputstream(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文件,如下所示:

public class test {
 /**
  * status : 0
  * intro : byhieg
  * shopname : byhige
  * message : 查询成功
  */
 private int status;
 private string intro;
 private string shopname;
 private string message;
 public int getstatus() {
  return status;
 }
 public void setstatus(int status) {
  this.status = status;
 }
 public string getintro() {
  return intro;
 }
 public void setintro(string intro) {
  this.intro = intro;
 }
 public string getshopname() {
  return shopname;
 }
 public void setshopname(string shopname) {
  this.shopname = shopname;
 }
 public string getmessage() {
  return message;
 }
 public void setmessage(string message) {
  this.message = message;
 }
}

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

test result = new gson().fromjson(response.body().string,test.class);

总结

简单介绍了okhttp的使用,对于一些高级用法请关注下篇文章,本人水平有限,如有错误,还望指正。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持移动技术网!

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网