OkHttp用法

一.概述

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

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

推荐阅读更多精彩内容

  • 这篇文章主要讲 Android 网络请求时所使用到的各个请求库的关系,以及 OkHttp3 的介绍。(如理解有误,...
    小庄bb阅读 1,150评论 0 4
  • OkHttp解析系列 OkHttp解析(一)从用法看清原理OkHttp解析(二)网络连接OkHttp解析(三)关于...
    Hohohong阅读 20,971评论 4 58
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,857评论 25 707
  • 前言 作为一个安卓开发,我们很少会碰到需要调试sp文件和数据库的情况,但是,如果碰到了,去翻查数据库文件,然后各种...
    feisher阅读 1,167评论 3 4
  • 明明理解 却烦了又烦 不断伤害 或许太亲近 以为是理所当然 再后悔 已经来不及 亲近的时光已被 消耗殆尽 算不算晚呢
    一个小疯子阅读 129评论 0 1