IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 网络框架之okhttp源码解析 -> 正文阅读

[移动开发]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 {
                //响应成功
            }
        });

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 {

                }
            }
        });

okhttp请求流程与源码解析

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

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

同步请求 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)//直接去正在运行的同步队列中取值
}

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

异步请求

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()
  }
}

上面可以看出,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 即可取货!!!

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-06-26 17:00:33  更:2022-06-26 17:00:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 3:27:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码