OkHttp用法

作者: Destiny_ZRJ | 来源:发表于2017-03-28 12:25 被阅读12125次

    一.概述

    Okhttp集成有多种,一种就是直接下载它的jar包但是并不推荐,一种是Maven方式去构建,这种在java程序里用的会比较多

    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>3.6.0</version>
    </dependency>
    

    在android程序里,我们一般用Gradle,把这句话加入build.gradle。

    compile 'com.squareup.okhttp3:okhttp:3.6.0'
    

    这样子就集成进去了
    集成后这里要注意一点:


    图片.png

    OkHttp是要依赖于okio的,因为所有的http请求都是基于流的,okio它是对流的再次封装的一个工具类

    二.使用

    一.Get请求

            OkHttpClient client = new OkHttpClient();
            //创建一个Request
            Request request = new Request.Builder()
                    .get()
                    .url(url)
                    .build();
            //通过client发起请求
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.isSuccessful()) {
                    // String str = response.body().string();
                    }
        
                }
            });
    

    以上就是get请求方式
    1.先实例化okhttp,构建一个request,使用的是get方式,放入一个url地址就可以了,也可以通过Request.Builder设置更多的参数。
    2.然后通过client发起一个请求,放入队列。等待任务完成,在Callback中取结果。
    3.通过response.body().string()获取返回来的字符串。
    这个body()其实就是ResponseBody的对象

     /**
       * Returns a non-null value if this response was passed to {@link Callback#onResponse} or returned
       * from {@link Call#execute()}. Response bodies must be {@linkplain ResponseBody closed} and may
       * be consumed only once.
       *
       * <p>This always returns null on responses returned from {@link #cacheResponse}, {@link
       * #networkResponse}, and {@link #priorResponse()}.
       */
      public ResponseBody body() {
        return body;
      }
    

    ResponseBody里面涉及到一些流的传输,里面有很多方法,常用的 就是string()。

    二.Post请求

    From表单形式

            OkHttpClient client = new OkHttpClient();
            RequestBody body = new FormBody.Builder().add("username","xiaoyi").build();
            Request request = new Request.Builder()
                    .post(body)
                    .url(url).
                    build();
            client.newCall(request).enqueue(new Callback() {...});
    

    JSON参数形式

            OkHttpClient client = new OkHttpClient();
            RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
            Request request = new Request.Builder()
                    .post(body)
                    .url(url).
                            build();
            client.newCall(request).enqueue(new Callback() {...});
    

    get请求和post请求没什么太大区别,post中RequestBody是必须要构建的。

    三.文件上传

            OkHttpClient client = new OkHttpClient();
            RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), fiDatale);
            RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file", "head_img", fileBody)
                    .addFormDataPart("name", "xiaoyi").build();
    
            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();
    
            client.newCall(request).enqueue(new Callback() {...});
    

    addFormDataPart和addPart并没有什么区别,只是addFromDataPart进行了封装

      /** 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 static Part createFormData(String name, String value) {
          return createFormData(name, null, RequestBody.create(null, value));
        }
    
        public static Part createFormData(String name, String filename, RequestBody body) {
          if (name == null) {
            throw new NullPointerException("name == null");
          }
          StringBuilder disposition = new StringBuilder("form-data; name=");
          appendQuotedString(disposition, name);
    
          if (filename != null) {
            disposition.append("; filename=");
            appendQuotedString(disposition, filename);
          }
    
          return create(Headers.of("Content-Disposition", disposition.toString()), body);
        }
    

    四.文件下载

            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url(url)
                    .build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.isSuccessful()){
                        downlodefile(response, Environment.getExternalStorageDirectory().getAbsolutePath(),"text.txt");
                    }
                }
            });
    

    文件下载就是从response中得到inputStream,做写文件操作

        private void downlodefile(Response response, String url, String fileName) {
            InputStream is = null;
            byte[] buf = new byte[2048];
            int len = 0;
            FileOutputStream fos = null;
            try {
                is = response.body().byteStream();
                //文件大小
                long total = response.body().contentLength();
                File file = new File(url, fileName);
                fos = new FileOutputStream(file);
                long sum = 0;
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);
    //                进度条
    //                sum += len;
    //                int progress = (int) (sum * 1.0f / total * 100);
                }
                fos.flush();
                Log.e("xxxxxxxx", "下载成功");
            } catch (Exception e) {
            } finally {
                try {
                    if (is != null)
                        is.close();
                } catch (IOException e) {
                }
                try {
                    if (fos != null)
                        fos.close();
                } catch (IOException e) {
                }
            }
        }
    

    五.Interceptors

    Interceptors是Okhttp中的拦截器,官方介绍拦截器是一个强大的监听器,可以重写,重试请求(calls)详细了解可以看下Okhttp-wiki 之 Interceptors 拦截器,这篇文章可以算是中文版。

      Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(retryAndFollowUpInterceptor);
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        interceptors.add(new CacheInterceptor(client.internalCache()));
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
          interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));
    
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
        return chain.proceed(originalRequest);
      }
    

    从这可以发现okhttp在处理网络响应时采用的是拦截器机制。okhttp用ArrayList对interceptors进行管理,interceptors将依次被调用。

    interceptors.png
    如上图:
    1.橙色框内是okhttp自带的Interceptors的实现类,它们都是在call.getResponseWithInterceptorChain()中被添加入 InterceptorChain中,实际上这几个Interceptor都是在okhttp3后才被引入,它们非常重要,负责了重连、组装请求头部、读/写缓存、建立socket连接、向服务器发送请求/接收响应的全部过程。

    2.在okhttp3之前,这些行为都封装在HttpEngine类中。okhttp3之后,HttpEngine已经被删去,取而代之的是这5个Interceptor,可以说一次网络请求中的细节被解耦放在不同的Interceptor中,不同Interceptor只负责自己的那一环节工作(对Request或者Response进行获取/处理),使得拦截器模式完全贯穿整个网络请求。

    3.用户可以添加自定义的Interceptor,okhttp把拦截器分为应用拦截器和网络拦截器

     public class OkHttpClient implements Cloneable, Call.Factory {
      final List<Interceptor> interceptors;
      final List<Interceptor> networkInterceptors;
      ......
      }
    

    (1)调用OkHttpClient.Builder的addInterceptor()可以添加应用拦截器,只会被调用一次,可以处理网络请求回来的最终Response
    (2)调用addNetworkInterceptor()可以添加network拦截器,处理所有的网络响应(一次请求如果发生了redirect ,那么这个拦截器的逻辑可能会被调用两次)
    4.Application interceptors与Network Interceptors

    应用拦截器
    不需要担心中间过程的响应,如重定向和重试.
    总是只调用一次,即使HTTP响应是从缓存中获取.
    观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
    允许短路而不调用 Chain.proceed(),即中止调用.
    允许重试,使 Chain.proceed()调用多次.
    
    网络连接器
    能够操作中间过程的响应,如重定向和重试.
    当网络短路而返回缓存响应时不被调用.
    只观察在网络上传输的数据.
    携带请求来访问连接.
    

    参考文章:
    OkHttp源码解析——HTTP请求的逻辑流程
    Okhttp-wiki 之 Interceptors 拦截器

    总结

    OkHttp的简单介绍就是这样,有兴趣的话可以自己封装起来,用起来方便些。后期有时间我会自己封装一个,等到时候加进来。理解里面用到的东西我认为才是最重要的。

    相关文章

      网友评论

        本文标题:OkHttp用法

        本文链接:https://www.haomeiwen.com/subject/jrwznttx.html