网络---OkHttp使用

Android网络编程Okhttp3用法详解   (封装的不错)

来自 <https://blog.csdn.net/baidu_33634330/article/details/77680289>

 

AndroidOKHttp3拦截器的使用方法(缓存的使用)

来自 <http://www.jb51.net/article/137366.htm

 

OkHttpUtils 一个专注于让网络请求更简单的框架

来自 <https://juejin.im/entry/5769f978d342d300580f4328>

 

 

一、前言

自从Android4.4开始,google已经开始将源码中的HttpURLConnection替换为OkHttp,而在Android6.0之后的SDK中google更是移除了对于HttpClient的支持,而市面上流行的Retrofit同样是使用OkHttp进行再次封装而来的。由此看见学习OkHttp的重要性。

本篇文章是以当前最新的版本3.5.0为例(2.0及以上版本版本与3.0以上版本存在较大差异,本文不做深入讨论,请自行百度),使用AndroidStuido作为开发环境,带领大家简单的熟悉OKHttp的使用情况。作为《Android网络编程》系类文章之一,后面的文章会围绕OKHttp3做逐渐深入的探讨。这篇文章我们要达到的目的就是:不深究,简单明了,可以直接粘贴复制。

创建者设计模式.

 

okHttp、volley、android-async-http对比:

  • volley是一个简单的异步http库,仅此而已。缺点是不支持同步,这点会限制开发模式;不能post大数据,所以不适合用来上传文件
  • android-async-http。与volley一样是异步网络库,但volley是封装的httpUrlConnection,它是封装的httpClient,而android平台不推荐用HttpClient了,所以这个库已经不适合android平台了。
  • okhttp是高性能的http库,支持同步、异步,而且实现了spdy、http2、websocket协议,api很简洁易用,和volley一样实现了http协议的缓存。

来自 <http://blog.csdn.net/baidu_33634330/article/details/77680289>

 

 

二、使用前的准备

2.1 官方文档

要知道学习一门新技术,最好的资料永远是官方文档:

OkHttp官方介绍

github源码

2.2 Android Studio配置gradle环境:

compile 'com.squareup.okhttp3:okhttp:3.5.0'
compile 'com.squareup.okio:okio:1.11.0'

2.3 添加网络权限

不要忘记添加权限啊,这也是常常被开发忽略的地方

<uses-permission android:name="android.permission.INTERNET"/>

三、使用教程

3.1 Http Get

3.1.1 异步的Get

在Http请求中最常见的就是get方法了,在大多数的使用场景中,我们使用的都是异步的Get请求,下面我们就是用OkHttp的异步Get去请求一下百度的首页。

        // step 1: 创建 OkHttpClient 对象   
        OkHttpClient okHttpClient =
new OkHttpClient();

       // step 2:创建一个请求,不指定请求方法时默认是GET。
        Request.Builder requestBuilder =
new Request.Builder().url("http://www.baidu.com");
       
//可以省略,默认是GET请求
        requestBuilder.method(
"GET",null);

      // step3:创建 Call 对象
       
Call call =okHttpClient.newCall(requestBuilder.build());

       //step 4:开始异步请求
       
call.enqueue(new Callback() {
           
@Override
            public void onFailure(Callcall, IOException e) {
               
// TODO: 17-1-4  请求失败
            }

  @Override

            public void onResponse(Call call, Responseresponse) throws IOException {
               
// TODO: 17-1-4 请求成功
               
//获得返回体
                ResponseBody body =response.body();
            }
        });

以上就是发送一个异步的Get请求的主要步骤。首先我们要创建一个OkHttpClick和Request.Builder()对象,再通过url()方法设置了网络地址来指定访问的目标,不仅如此 Request.Builder() 是支持链式编程的(返回体是本体)在这里可以设置这些方法哦:

Request.Builder()链式编程,在此不做探讨

接下来我们就要将OkHttpClick的对象与Request的对象建立起来联系,使用okHttpClick的newCall()方法得到一个Call对象,这个Call对象的作用就是相当于将请求封装成了一个任务,既然是任务,自然就会有execute()和cancel()等方法。

最后,我们希望以异步的方式去执行请求,所以我们调用的是call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。但要注意的是,call的回调是子线程,所以是不能直接操作界面的。使用时需要自行处理。当请求成功时就会回调onResponse()方法,我们可以看到返回的结果是 Response对象,在此我们比较关注的是请求中的返回体body(ResponseBody类型),大多数的情况下我们希望获得字符串从而进行json解析获得数据,所以可以通过body.string()的方式获得字符串。

 

3.1.2ResponseBody的 API,得到InputStream进行大文件传输

查看ResponseBody的API文档可以看到,body还可以获取byte[]、Reader、InputStream,其中最惊奇一点就是可以返回InputStream,这至少说明了OkHttp是可以支持大文件的下载的,这样一来我们就可以轻松的使用InputStream进行I/O方式的文件写入啦!!!。

 

让我们实现一下吧:

        //step 1: 不变的第一步创建 OkHttpClick
        OkHttpClient okHttpClient =
new OkHttpClient();

//step 2: 创建Requset

        Requestrequest = newRequest.Builder()
                .url(
"http://www.ssyer.com/uploads/org_2017010593503_775.jpg")
                .build();

//step 3:建立联系,创建Call

       mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Callcall, IOException e) {
            }

@Override

 public void onResponse(Call call, Responseresponse) {
                InputStream inputStream =response.body().byteStream();
                FileOutputStreamfileOutputStream = null;
                try {
                    File file = newFile(Environment.getExternalStorageDirectory() +
"大狮子.jpg");
                    fileOutputStream =
new FileOutputStream(file);
                    byte[] buffer = newbyte[2048];
                    int len =0;
                    while ((len =inputStream.read(buffer)) != -1) {
                       fileOutputStream.write(buffer, 0, len);
                    }
                   fileOutputStream.flush();
                } catch (IOException e){
                    e.printStackTrace();
                }

Log.d("downloadAsynFile", "文件下载成功");
            }
 });

3.1.3同步的Get

当然Get也支持阻塞方式的同步请求,不过在开发中这种方法很少被使用。上面我们也说了Call有一个execute()方法,你也可以直接调用call.execute()返回一个Response。然后利用isSuccessful()判读是否成功,进行相应的结果解析。

 

3.2 异步的Http Post

在看过了Get请求方式,相信你对于请求的用法也用基本的掌握了,Post的使用使用方法和Get虽然存在些许差异,但是本质是不变的。那么下面就让我们以携带键值对的Post为例,先熟悉一下Post的使用方法吧。

3.2.1 Post 上传键值对

        //step 1:同样的需要创建一个OkHttpClick对象
        OkHttpClient okHttpClient =
new OkHttpClient();

   //step 2: 创建  FormBody.Builder

        FormBodyformBody = newFormBody.Builder()
                .add(
"name","dsd")
                .build();

   //step 3: 创建请求

       Request request = new Request.Builder().url("http://www.baidu.com")
                .post(formBody)
  //.method("POST",null)
                .build();

   //step 4: 建立联系 创建Call对象

       okHttpClient.newCall(request).enqueue(new Callback() {
           
@Override
           
public void onFailure(Call call, IOException e) {
               
// TODO: 17-1-4 请求失败
            }

 @Override

            public void onResponse(Call call, Response response) throws IOException {
               
// TODO: 17-1-4 请求成功
            }
        });

是不是和Get很相似啊。大家都清楚,在使用Post的时候,参数是包含在请求体中的。所以我们通过FormBody,添加多个String键值对,然后为Request添加post(formBody)完成我们Request的构造。之后的步骤就和Get的步骤一样了,是不是很简单啊!

3.2.2 Post异步上传文件

直接上代码

       // step 1: 创建 OkHttpClient 对象
        OkHttpClient okHttpClient =
new OkHttpClient();

//step 2:创建 RequestBody 以及所需的参数
        //2.1 获取文件
       
File file = newFile(Environment.getExternalStorageDirectory() + "test.txt");
       
//2.2 创建 MediaType 设置上传文件类型
        MediaType MEDIATYPE =MediaType.parse(
"text/plain;charset=utf-8");
       
//2.3 获取请求体
        RequestBody requestBody =RequestBody.create(MEDIATYPE,
file);

//step 3:创建请求
        Request request =
new Request.Builder().url("http://www.baidu.com")
               .post(requestBody)
                .build();
 

//step 4 建立联系
       okHttpClient.newCall(request).enqueue(
new Callback() {
            @Override
            public void onFailure(Callcall, IOException e) {
               
// TODO: 17-1-4 请求失败
            }

@Override
           
public void onResponse(Call call, Responseresponse) throws IOException {
               
// TODO: 17-1-4 请求成功
            }
        });

当然这里需要添加权限滴,你是不是忘记了呢。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:
name="android.permission.WRITE_EXTERNAL_STORAGE"/>

第一步与之前都相同,但是从第二步开始就用了一定的差异了。在step2中我们需要通过MediaType.parse("text/plain;charset=utf-8")为上传文件设置一定类型(MIME)在这里我们上传的纯文本文件所以选择"text/plain类型,而编码格式为utf-8。下面为大家列出常见的文件类型,方便使用。

参数

说明

text/html

HTML格式

text/plain

纯文本格式

text/xml

XML格式

image/gif

gif图片格式

image/jpeg

jpg图片格式

image/png

png图片格式

application/xhtml+xml

XHTML格式

application/xml

XML数据格式

application/atom+xml

Atom XML聚合格式

application/json

JSON数据格式

application/pdf

pdf格式

application/msword

Word文档格式

application/octet-stream

二进制流数据

其实MIME文件类型特批多,有兴趣的朋友可以可参见w3school上的MIME 参考手册

上传类型

在创建RequestBody的时候可以看到,我们不仅仅可以上传File文件,还可以上传String,ByteString,byte数组等类型,其中上传byte数据时可以选择三个参数的creta方法,需要指定偏移量和需要写入的byte长度,哈哈这不是说明可以直接进行多线程、断点上传吗!通过这些类型,我们可以上传Json串,图片等内容真是方便又好用啊。

3.3添加请求头:

  1. private Request.Builder addHeaders() {  
  1.     Request.Builder builder = new Request.Builder()  
  2.             //addHeader,可添加多个请求头  header,唯一,会覆盖  
  3.             .addHeader("Connection""keep-alive")  
  4.             .addHeader("platform""2")  
  5.             .addHeader("phoneModel", Build.MODEL)  
  6.             .addHeader("systemVersion", Build.VERSION.RELEASE)  
  7.             .addHeader("appVersion""3.2.0")  
  8.             .header("sid""eyJhZGRDaGFubmVsIjoiYXBwIiwiYWRf");  
  9.     return builder;  
  10. }  

 

 

3.4拦截器使用

Interceptors拦截器——OkHttp3详细使用教程

来自 <https://blog.csdn.net/xx326664162/article/details/78044877>

OkHttp3中Interceptor的使用心得Request,Repons解析)

来自 <https://blog.csdn.net/lileirunning/article/details/53305603>

 

OkHttpInterceptors拦截器是一种强大的机制,可以监视,重写和重试Call请求。下面是一个简单的拦截器,它记录发出的请求和返回的响应。

在每一个拦截器中,一个关键部分就是使用chain.proceed(request)发起请求。这个简单的方法是所有HTTP工作发生的地方,生成与请求对应的响应。

多个拦截器可以连接使用。

假设有一个压缩拦截器和一个校验和拦截器:你需要决定数据是否先被压缩,然后校验和或者先校验和,然后再压缩。OkHttp使用列表来跟踪拦截器,并按顺序调用拦截器。

3.4.1应用拦截器  Application Interceptors

  • 不需要担心中间过程的响应,如重定向和重试.
  • 总是只调用一次,即使HTTP响应是从缓存中获取.
  • 观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
  • 允许短路而不调用 Chain.proceed(),即中止调用.
  • 允许重试,使 Chain.proceed()调用多次.
  • Application Interceptors应用程序拦截器(网络重定向不会再次执行)

不需要担心比如重定向和重试的中间响应。

总是被调用一次,即使HTTP响应结果是从缓存中获取的。

监控应用程序的原始意图。不关心例如OkHttp注入的头部字段If-None-Match。

允许短路,不调用Chain.proceed()。

允许重试并多次调用Chain.proceed()。

 

3.4.2网络拦截器 Network Interceptors

  • 能够操作中间过程的响应,如重定向和重试

(如果一次Request中进行了中转,则会执行两次NetworkInterceptors

  • 当网络短路而返回缓存响应时不被调用.
  • 只观察在网络上传输的数据,每次网络请求都会被拦截
  • 携带请求来访问连接.
  • Network Interceptors网络拦截器。(每次网络请求或重新定向都会执行)

能够对中间的响应进行操作比如重定向和重试。

当发生网络短路时,不调用缓存的响应结果。

监控数据,就像数据再网络上传输一样。

访问承载请求的连接Connection。

 

实际使用:

  • Log输出
  • 增加公共请求参数
  • 修改请求头
  • 对请求参数进行统一加密处理。
  • 服务器端错误码处理(时间戳异常为例)
  • 拦截不符合规则的URL。
  • 对请求或者返回参数设置统一的编码方式

3.4.3拦截器执行顺序代码:

来自 <http://blog.csdn.net/xx326664162/article/details/78044877>

OkHttpClientbuild=mOkHttpClient.newBuilder()

.addInterceptor(appInterceptor)

.addNetworkInterceptor(netInterceptor)

.build();

Requestrequest=newRequest.Builder()

.url("http://www.baidu.com")

.build();

build.newCall(request).enqueue(newCallback(){

@Override

publicvoidonFailure(Callcall,IOExceptione){

}

@Override

publicvoidonResponse(Callcall,Responseresponse)throwsIOException{

Lg.d("---Interceptor测试onResponse-----");

}

});

打印结果:

 appinterceptor:begin:http://www.publicobject.com/helloworld.txt

 networkinterceptor:begin:http://www.publicobject.com/helloworld.txt

 network interceptor:end

ify_callbackx509_store_ctx=0x7f6d12a6e0 arg=0x0

ify_callbackcalling verifyCertificateChain authMethod=ECDHE_RSA

 networkinterceptor:begin:https://publicobject.com/helloworld.txt

 network interceptor:end

 app interceptor:end

 

 

3.4.4自定义拦截器使用代码:

public class LoggingInterceptor implements Interceptor{

@Override

public Response intercept(Interceptor.Chain chain) throws IOException{

//这个chain里面包含了request和response,所以你要什么都可以从这里拿

//拦截请求,获取到该次请求的request

Request request = chain.request();

long t1=System.nanoTime();//请求发起的时间

Lg.i(String.format("发送请求%son%s%n%s",request.url(),chain.connection(),request.headers()));

 

 // 执行本次网络请求操作,返回response信息(使用chain.proceedrequest)发起请求)

Response response = chain.proceed(request);

long t2 = System.nanoTime();//收到响应的时间

 

//这里不能直接使用response.body().string()的方式输出日志

//因为response.body().string()之后,response中的流会被关闭,程序会报错,我们需要创建出一

//个新的response给应用层处理

ResponseBody responseBody = response.peekBody(1024*1024);

Lg.i(String.format("接收响应:[%s]%n返回json:【%s】%.1fms%n%s",response.request().url()responseBody.string(),

(t2-t1)/1e6d,response.headers()));

return response;

}

}

 

 

 

 

OkHttp3使用起来是不是很简单呢,但是每一次请求的步骤都有着大量重复的地方,这要是在实际开发中,还不把人累着啊,本着节约开

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页