• Android 网络框架之okhttp源码解析


    okhttp使用

    okhttp则分为Request请求与response响应。

    request请求体:每一个HTTP请求中都应该包含一个URL,一个GET或POST方法以及Header或其他参数,当然还可以含特定内容类型的数据流。

    response 响应码:响应则包含一个回复代码(200代表成功,404代表未找到),Header和定制可选的body。

    封装的okhttp库与okhttp使用:

    blog.csdn.net/xjz123456qq…

    基本请求(GET POST)

    GET

    Request.Builder builder = new Request.Builder();
            Request request = builder.get().url(url).build();
            Call call = client.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException error) {
                   //响应失败
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    //响应成功
                }
            });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    POST

    RequestBody body = RequestBody.create(JSON, jsonObject.toString());
     client.newCall(
                    new Request.Builder()
                            .url(url)
                            //      .headers()//添加头
                            .post(body)
                            .build()).enqueue(new Callback() {
    
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    LogUtil.i("http response " + response);
                    if (response.isSuccessful()) {
    
                        }
                    }else {
    
                    }
                }
            });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    okhttp请求流程与源码解析

    由上面请求可以看出同步与异步,都是通过newCall()去实现的,那么newCall()到底了实现了什么呢?

    //返回了一个Call对象
    override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
    
    • 1
    • 2

    同步请求 call.execute()

    override fun execute(): Response {
      //先判断一下当前是否请求过
      check(executed.compareAndSet(false, true)) { "Already Executed" }
    
      timeout.enter()
      callStart()
      try {
        //分发器进行分发
        client.dispatcher.executed(this)
        return getResponseWithInterceptorChain()// 走拦截器
      } finally {
        client.dispatcher.finished(this)//完成后的回调
      }
    }
    
    /** Used by [Call.execute] to signal it is in-flight. */
    @Synchronized internal fun executed(call: RealCall) {
      runningSyncCalls.add(call)//直接去正在运行的同步队列中取值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    源码可以看到,同步拦截器,直接去正在执行的同步队列中取值。

    异步请求

    override fun enqueue(responseCallback: Callback) {
    //先判断当前这个call是否已经执行,执行了抛异常
      check(executed.compareAndSet(false, true)) { "Already Executed" }
    
      callStart()
      client.dispatcher.enqueue(AsyncCall(responseCallback))//走异步的分发
    }
    
    internal fun enqueue(call: AsyncCall) {
      synchronized(this) {
        readyAsyncCalls.add(call)//先将任务放到等待队列中
    
        // Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
        // the same host.
        if (!call.call.forWebSocket) {
          val existingCall = findExistingCallWithHost(call.host)
          if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
        }
      }
      promoteAndExecute()
    }
    
    private fun promoteAndExecute(): Boolean {
      this.assertThreadDoesntHoldLock()
    
      val executableCalls = mutableListOf<AsyncCall>()
      val isRunning: Boolean
      synchronized(this) {
    
        val i = readyAsyncCalls.iterator()
        //迭代等待执行异步请求
        while (i.hasNext()) {
          val asyncCall = i.next()
          //正在执行异步请求的任务数 不能大于 64个
          if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
          //同一个host的请求数 不能大于5
          if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
    
          i.remove()
          asyncCall.callsPerHost.incrementAndGet()
          executableCalls.add(asyncCall)  //需要开始执行的任务集合,创建的一个临时队列
          runningAsyncCalls.add(asyncCall)//将要执行的任务放到正在执行异步的队列中
        }
        isRunning = runningCallsCount() > 0
      }
    
      //对临时队列里的任务进行处理,迭代处理
      for (i in 0 until executableCalls.size) {
        val asyncCall = executableCalls[i]
        asyncCall.executeOn(executorService)//放到线程池中进行处理
      }
    
      return isRunning
    }
    
    //异步处理任务的源码
    override fun run() {
      threadName("OkHttp ${redactedUrl()}") {
        var signalledCallback = false
        timeout.enter()
        try {
          // 执行请求,走拦截器
          val response = getResponseWithInterceptorChain()
          signalledCallback = true
          responseCallback.onResponse(this@RealCall, response)
        } catch (e: IOException) {
          if (signalledCallback) {
            // Do not signal the callback twice!
            Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
          } else {
            responseCallback.onFailure(this@RealCall, e)
          }
        } catch (t: Throwable) {
          cancel()
          if (!signalledCallback) {
            val canceledException = IOException("canceled due to $t")
            canceledException.addSuppressed(t)
            responseCallback.onFailure(this@RealCall, canceledException)
          }
          throw t
        } finally {
          client.dispatcher.finished(this)//完成之后的回调
        }
      }
    }
    
    /** Used by [Call.execute] to signal completion. */
    internal fun finished(call: RealCall) {
      finished(runningSyncCalls, call)
    }
    
    private fun <T> finished(calls: Deque<T>, call: T) {
      val idleCallback: Runnable?
      synchronized(this) {
        if (!calls.remove(call)) throw AssertionError("Call wasn't in-flight!")
        idleCallback = this.idleCallback
      }
    
      val isRunning = promoteAndExecute()//完成这次任务请求后,去进行下一次请求
    
      if (!isRunning && idleCallback != null) {
        idleCallback.run()
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    上面可以看出,RealCall中有三个队列

    1、正在执行的同步队列
    2、正在执行的异步队列
    3、准备执行的异步队列,任务进行排队准备的队列

    异步请求流程:

    1、enqueue()后,先判断当前任务是否被执行,没有执行走分发器的分发
    2、先把任务放到等待执行的异步队列readyAsyncCalls中
    3、对等待队列进行一个迭代,判断正在执行的任务数是否大于64 ,相同的host是否大于5
    4、正在执行的异步队列中任务数大于64,则不能执行,继续在等待队列等待,如果当前任务的host>5,则进行下一个任务的执行判断
    5、将要执行的任务放到正在执行的任务中,并且放到一个临时对列里,调线程池执行
    6、线程池执行后,走拦截器,完成后,走回调。
    7、拦截器走责任链模式,五大拦截器执行,完成后,回调。
    8、完成后,重新触发promoteAndExecute(),进行下一个任务请求

    五大拦截器

    1、RetryAndFolloeUpInterceptor:重试定向拦截器

    判断用户是否取消了拦截器,获得结果后,将状态码去判断是否需要重定向,满足条件重启所有拦截器

    2、BrisgeInterceptor:桥接拦截器

    对传参后进行的网络处理:Header, Body处理,自动将HTTP协议,请求头,,GZIP压缩,等处理,保存cookie接口去处理

    3、CacheInterceptor: 缓存拦截器

    请求一个不会改变的资源,读取之前判断当前是否有缓存,有缓存就调缓存直接回调,没有,走连接拦截器

    4、Connection:连接拦截器

    缓存没有命中, 走连接拦截器,找到与服务器的连接,或者创建一个连接,获取对应的socket流,获取结果后不进行额外处理,直接走请求服务拦截器

    5、CallServerInterceptor:请求服务拦截器

    拿到连接器后,将数据包装在class发给服务端,得到响应,与服务器通信,向服务器发送数据,解析读取的响应数据,再一步一步返回回去

    责任链模式

    类似递归调用,由上往下执行,执行后,结果由下往上返回。

    最后为了帮助到大家有效率的学好 Android 百大框架知识点,特意整理了一份Android 百大框架进阶滋尿,帮助大家在技术的道路上更进一步,大家有需要的 可以后台私信我回复 666 即可取货!!!

  • 相关阅读:
    Docker的基本操作
    企业级win10电脑下同时存在Python3.11.7Python3.6.6,其中Python3.6.6是后装的【过程与踩坑复盘】
    STM32F103学习笔记(9)——NB-IoT模块BC26使用
    1164 Good in C
    校园小情书微信小程序,社区小程序前后端开源,校园表白墙交友小程序
    【scikit-learn基础】--『监督学习』之 逻辑回归分类
    时序预测 | MATLAB实现ICEEMDAN-iMPA-BiLSTM时间序列预测
    【微信小程序系列:五】小程序适老化自动适配工具miniprogram-elder-transform---微信老年关怀模式下小程序字体适配微信字体
    【饭谈】测试行业找工作最看重什么?
    【漏洞复现】Aapache_Tomcat_AJP协议_文件包含漏洞(CVE-2020-1938)
  • 原文地址:https://blog.csdn.net/weixin_61845324/article/details/125426167