美文网首页
Android 网络请求框架okhttp学习笔记

Android 网络请求框架okhttp学习笔记

作者: 斌林诚上 | 来源:发表于2020-04-05 20:36 被阅读0次

    ——谁不是一边受伤一边成长,谁不是一面流泪一面坚强。

    前言

    这篇给Okhttp做个记录。主要还是对自己阅读源码后的一个总结。当然距离上次看过源码已经1年多。写这篇的原因还是担心过太久又忘了。 所以复习并总结一下。本篇不会有太多的拓展,主要以介绍性为主。

    一、简介

    github地址:GitHub

    (1)是什么

    ——是目前最火的开源网络请求框架。有人可能会想到Retrofit,当然Retrofit也是基于okhttp的一个二次封装库。

    (2)有什么用

    ——提供更方便的网络请求方式。通过该库可以更加简洁的获取到网络数据。

    二、怎么用

    步骤:

    (1)添加依赖

     implementation "com.squareup.okhttp3:okhttp:3.5.0"
    

    (2)创建OkHttpClient

    OkHttpClient okHttpClient = new OkHttpClient();
    

    (3)构建Request请求信息

    //构建请求信息:连接请求url 请求方法method 请求头部headers 请求体body 标签tag
    
    Request request = new Request.Builder().url("xxxxxx").get().build();
    

    (4)创建Call对象

    Call call = okHttpClient.newCall(request);
    

    (5)创建同步请求

            try {
                Call call = okHttpClient.newCall(request);
                Response execute = call.execute();
                String success = execute.body().toString();
                Log.e(TAG, "onCreate: "+success );
            } catch (IOException e) {
                e.printStackTrace();
            }
    

    (6)创建异步请求

    okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
    
                }
            });
    

    (7)总结

            //创建OkhttpClient
            OkHttpClient okHttpClient = new OkHttpClient();
            //构建请求信息:连接请求url 请求方法method 请求头部headers 请求体body 标签tag
            Request request = new Request.Builder().url("xxxxxx").get().build();
            //同步
            try {
                Call call = okHttpClient.newCall(request);
                Response execute = call.execute();
                String success = execute.body().toString();
                Log.e(TAG, "onCreate: "+success );
            } catch (IOException e) {
                e.printStackTrace();
            }
            //异步
            okHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
    
                }
            });
    

    三、原理

    (1)创建OkHttpClient:OkHttpClient okHttpClient = new OkHttpClient();

    //1.创建OkhttpClient 有两种方式
    (1)OkHttpClient okHttpClient = new OkHttpClient();
    
    (2)OkHttpClient build = new OkHttpClient.Builder().build();
    
    第一种OkhttpClient 采用默认配置信息
    第二种通过Builder 可自定义配置信息 
    
      //默认配置 Builder()
      public OkHttpClient() {
        this(new Builder());
      }
    
      //OkhttpClient 配置信息
      public Builder() {
          //创建Dispatcher: 该对象内部维护着一个线程池,
          //管理OkhttpClient的线程操作。通过该对象可执行异步操作。
          dispatcher = new Dispatcher();
          protocols = DEFAULT_PROTOCOLS;//定义默认协议
          connectionSpecs = DEFAULT_CONNECTION_SPECS;//定义连接方式
          proxySelector = ProxySelector.getDefault();//使用默认代理服务
          cookieJar = CookieJar.NO_COOKIES;//定义 Cookie
          socketFactory = SocketFactory.getDefault();//使用默认的SocketFactory
          hostnameVerifier = OkHostnameVerifier.INSTANCE;//定义默认证书
          certificatePinner = CertificatePinner.DEFAULT;//定义不受信任的证书
          //设置网络身份验证
          proxyAuthenticator = Authenticator.NONE;
          authenticator = Authenticator.NONE;
          //连接池:管理HTTP和HTTP/2连接的重用,以减少网络延迟
          connectionPool = new ConnectionPool();
          dns = Dns.SYSTEM;
          //定义HTTPS 和 HTTP 之间的重定向
          followSslRedirects = true;
          followRedirects = true;
          //定义是否失败重连
          retryOnConnectionFailure = true;
           //定义连接超时连接
          connectTimeout = 10_000;
            //定义读取超时连接
          readTimeout = 10_000;
          //定义写入超时连接
          writeTimeout = 10_000;
           //定义Web socket ping 间隔
          pingInterval = 0;
        }
    

    进阶:还可以通过addNetworkInterceptor(Interceptor interceptor)与addInterceptor(Interceptor interceptor)添加自定义拦截器

    addInterceptor()方法添加的拦截器是放在addNetworkInterceptor()前面的。

    addNetworkInterceptor() 方法添加的网络拦截器,则是在非 WebSocket 请求时。

    添加在 ConnectInterceptor 和 CallServerInterceptor 之间的。

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

    (2)构建Request请求信息:Request request = new Request.Builder().url("xxxxxx").get().build();

    //请求信息
    public final class Request {
      final HttpUrl url; //配置url
      final String method;//配置请求方法
      final Headers headers;// 配置请求头部
      final RequestBody body;//配置请求体
      final Object tag; //标记请求
    }
    
    //使用默认get请求 与默认头部
    public Builder() {
       this.method = "GET";
       this.headers = new Headers.Builder();
    }
    
    //创建Request 请求
    public Request build() {
       if (url == null) throw new IllegalStateException("url == null");
       return new Request(this);
    }
    //配置Request 信息
    Request(Builder builder) {
       this.url = builder.url;
       this.method = builder.method;
       this.headers = builder.headers.build();
       this.body = builder.body;
       this.tag = builder.tag != null ? builder.tag : this;
    }
    

    (3)OkHttpClient 关联 Request: Call call = okHttpClient.newCall(request);

     /**
     * 1.创建 RealCall()
     */
     @Override public Call newCall(Request request) {
        return new RealCall(this, request, false /* for web socket */);
      }
    
    /**
     * 2\. RealCall 持有 OkHttpClient对象与Request对象 并创建 重定向拦截器
     * 主要作用是发起请求
     */
      RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
        this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
      }
    
    /**
     * 3.重定向拦截器  持有OkHttpClient 对象
     */
     public RetryAndFollowUpInterceptor(OkHttpClient client, boolean forWebSocket) {
        this.client = client;
        this.forWebSocket = forWebSocket;
      }
    

    (4)发起请求

    //同步请求

     //调用 RealCall 对象execute() 发起同步请求
    @Override public Response execute() throws IOException {
        synchronized (this) {
    //判断是否在执行
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
    //将一些堆栈跟踪的信息存储于重定向拦截器
        captureCallStackTrace();
        try {
    //将Call添加到同步运行队列中
     client.dispatcher().executed(this);
    //通过okHttpClient调用调度器(dispatcher)执行拦截器链 ——> (1) 
    Response result = getResponseWithInterceptorChain();
          if (result == null) throw new IOException("Canceled");
          return result;
        } finally {
          client.dispatcher().finished(this);
        }
      }
    
    // (1)通过okHttpClient调用调度器(dispatcher)执行拦截器链:
    // 主要作用:连接服务器,处理请求体与响应体。最终获取到Response 数据。
    // okHttpClient 核心方法
    Response getResponseWithInterceptorChain() throws IOException {
        // 1.创建容器存储拦截器
        List<Interceptor> interceptors = new ArrayList<>();
        // 2.添加自定义拦截器
        interceptors.addAll(client.interceptors());
        // 3.添加重定向拦截器 主要作用
        //(1)根据异常结果或者响应结果判断是否要进行重新请求
        interceptors.add(retryAndFollowUpInterceptor);
        // 4.添加网络连接桥拦截器 主要作用:
        //(1)将用户构建的一个 Request 请求转化为能够进行网络访问的请求
        //(2)将网络请求回来的响应 Response 转化为用户可用的 Response
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        // 5.添加缓存拦截器 主要作用:
        // (1)创建缓存策略 缓存响应数据
        interceptors.add(new CacheInterceptor(client.internalCache()));
        // 6.添加连接拦截器 主要作用:
        // (1)与服务端 建立连接,并且获得通向服务端的输入和输出流对象
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
            // 7.添加 自定义网络拦截器
          interceptors.addAll(client.networkInterceptors());
        }
        // 8.添加 服务回调拦截器 主要作用:
         // (1)使用 HttpStream 与服务器进行数据的读写操作的
        interceptors.add(new CallServerInterceptor(forWebSocket));
         // 9.创建拦截器链 并启动
        Interceptor.Chain chain = new RealInterceptorChain(
            interceptors, null, null, null, 0, originalRequest);
        return chain.proceed(originalRequest);
      }
    

    //异步请求

    //调用该方法 执行异步请求
    @Override public void enqueue(Callback responseCallback) {
        //判断是否重复执行
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already Executed");
          executed = true;
        }
        //将一些堆栈跟踪的信息存储于重定向拦截器
        captureCallStackTrace();
        // 详情——> (1)   (2)
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
      }
    
    (1)异步请求策略
      synchronized void enqueue(AsyncCall call) {
        //判断运行的异步线程数是否小于最大的请求数    核心线程数小于最大的运行数
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
        // 运行的异步线程数未满 则执行新的任务caLl
          runningAsyncCalls.add(call);
          executorService().execute(call);
        } else {
        // 运行的异步线程数达到最大值 则将新的任务添加到等待的队列中
          readyAsyncCalls.add(call);
        }
      }
    
    (2)创建AsyncCall 继承NamedRunnable 对象
    并执行NamedRunnable 的run()
    
      @Override public final void run() {
        String oldName = Thread.currentThread().getName();
        Thread.currentThread().setName(name);
        try {
            //——> (3)
          execute();
        } finally {
          Thread.currentThread().setName(oldName);
        }
      }
    (3) 最终执行AsyncCall 的 execute() 
     @Override protected void execute() {
          boolean signalledCallback = false;
          try {
            //同样执行拦截器链 获取到Response 
            Response response = getResponseWithInterceptorChain();
            if (retryAndFollowUpInterceptor.isCanceled()) {
              signalledCallback = true;
              responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
            } else {
              signalledCallback = true;
              responseCallback.onResponse(RealCall.this, response);
            }
          } catch (IOException e) {
            if (signalledCallback) {
              // Do not signal the callback twice!
              Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
            } else {
              responseCallback.onFailure(RealCall.this, e);
            }
          } finally {
            client.dispatcher().finished(this);
          }
        }
      }
    

    通过源码可以清楚的了解到,OKHTTP 该库获取网络请求数据的核心实现是通过责任链模式。

    由各个拦截器协作完成对网络服务器的数据获取。

    重要的过程还是要通过了解各个拦截器实现。才能清楚如何连接网络。并获取到数据。

    这里就不详细记录。 谢谢各位浏览。 。。。

    四、内容推荐

    若您发现文章中存在错误或不足的地方,希望您能指出!

    相关文章

      网友评论

          本文标题:Android 网络请求框架okhttp学习笔记

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