OkHttp简析及实现

OkHttp简析及实现

还记得 2015 年刚开始学习 Android 那会,还在为 Eclipse 项目中集成 Afinal.jar 、 Volley.jar 爆红而发愁,一晃而过到现在的 2020 年,见证了 AndroidStudio 的兴起。就这短短的5年时间,很多工具和技术都进行了更新换代或者在升级

今天我们就看看经过官方承认并使用的网络请求框架 OkHttp

OkHttp简析

使用

接入 OkHttp

先来康康怎么接入,直接 gradle 中一行代码就搞定了。确实比之前还要下载相关 jar 包,然后在复制粘贴,然后在添加相关配置要简单的多了

implementation 'com.squareup.okhttp3:okhttp:4.8.1'

如果一行代码搞不定的话,那就再加几行 - -~,在项目的 build 文件中添加国内镜像

buildscript {
    repositories {
        maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
        maven { url "https://dl.bintray.com/thelasterstar/maven/" }
    }
}
allprojects {
    repositories {
        maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
        maven { url "https://dl.bintray.com/thelasterstar/maven/" }
    }
}
调用

调用就比较简单了,构建请求端,发送请求,回调接受请求结果。

//创建请求端
OkHttpClient()
        //创建请求体
        .newCall(Request.Builder().url("https://www.baidu.com").build())
        //创建请求完成后的回调接口
        .enqueue(object :Callback{
            override fun onFailure(call: Call, e: IOException) {
                
            }

            override fun onResponse(call: Call, response: Response) {
                
            }
        })

使用方面无甚可说,主要就是在项目中应用的时候,尽量在 okhttp 之上在包装一层。这样如果后期需要更换底层 okhttp 的时候对于项目改动就比较小了。

下面就从源码简单分析一下 okhttp 的实现

源码简析

注意看题目,是源码简析,如果你想看完这篇文章就可以搞清楚 okhttp 的源码,那就要大失所望了。不是咱家不想写呀,主要是源码里面的细节处理和架构的设计,用文字表达就没有那个感觉了,还是得去撸源码,所以这里就只是把整个流程梳理一遍,具体的细枝末节都没有去说明。比如:建造者模式、责任链模式、线程池、线程安全等,在源码中都可以找到相应的影子。

闲话不多说,先来一张简易的调用流程图

在这里插入图片描述

从上面的调用流程图逐步分析源码,看看涉及到的类的相关调用

/**
 *  OkHttpClients Should Be Shared
 * 意思就是 OkHttpClient 这个玩意在应用中创建一次就可以进行全局共享了,没有比较多次创建。
 * 所以我们上面那个写法有点不规范哈,别纠结
 */
open class OkHttpClient internal constructor(
  builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
    //① 构造一个 OkHttpClient 请求端
    //这里的 builder 用到了建造者模式。里面主要是一些配置相关信息,感兴趣可以撸源码,这里不多说
    constructor() : this(Builder())

    /** Prepares the [request] to be executed at some point in the future. */
    //通过传进来的 request 请求体,构造一个真正的请求结构 RealCall ,将来便于添加到线程池中运行
    //② 调用 newCall 方法构造一个真正的请求体
    override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
}

class RealCall(
  val client: OkHttpClient,
  /** The application's original request unadulterated by redirects or auth headers. */
  val originalRequest: Request,
  val forWebSocket: Boolean
) : Call {
  // ③ 调用该方法将异步请求 AsyncCall 加入线程池执行
  override fun enqueue(responseCallback: Callback) {
    check(executed.compareAndSet(false, true)) { "Already Executed" }

    callStart()
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }
  internal inner class AsyncCall(
    private val responseCallback: Callback
  ) : Runnable {
    
    override fun run() {
      threadName("OkHttp ${redactedUrl()}") {
        var signalledCallback = false
        timeout.enter()
        try {
          // ④ 线程执行 run 方法请求网络返回结果 response
          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)
        }
      }
    }
  }
}

好了,okhttp 的调用流程这里就结束了,够简单吧,不过这是真的啊,就是这么个流程,剔除了一下繁杂的判断和细节处理。

当然,上面那个没有说到 okhttp 的精髓所在,就是步骤 ④ 中的 getResponseWithInterceptorChain 这个方法,下面我们进去看看。

class RealCall(val client: OkHttpClient, val originalRequest: Request, 
    val forWebSocket: Boolean) : Call {
  @Throws(IOException::class)
  internal fun getResponseWithInterceptorChain(): Response {
    // Build a full stack of interceptors.
    //构建完整的拦截器堆栈
    val interceptors = mutableListOf<Interceptor>()
    // 添加用户自定义拦截器
    interceptors += client.interceptors
    // 重试拦截器
    interceptors += RetryAndFollowUpInterceptor(client)
    // 桥接拦截器
    interceptors += BridgeInterceptor(client.cookieJar)
    // 缓存拦截器
    interceptors += CacheInterceptor(client.cache)
    // connect 请求拦截器
    interceptors += ConnectInterceptor
    if (!forWebSocket) {
      //网络拦截器 
      interceptors += client.networkInterceptors
    }
    // 调用服务拦截器
    interceptors += CallServerInterceptor(forWebSocket)

    // 创建一个真正的拦截链条,并且将当前的拦截器集合传递进去
    val chain = RealInterceptorChain(
        call = this,interceptors = interceptors,index = 0,exchange = null,
        request = originalRequest,connectTimeoutMillis = client.connectTimeoutMillis,
        readTimeoutMillis = client.readTimeoutMillis,writeTimeoutMillis = client.writeTimeoutMillis)

    var calledNoMoreExchanges = false
    try {
      //调用链条的第一个拦截器的处理方法,并返回处理结果
      val response = chain.proceed(originalRequest)
      if (isCanceled()) {
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
      calledNoMoreExchanges = true
      throw noMoreExchanges(e) as Throwable
    } finally {
      if (!calledNoMoreExchanges) {
        noMoreExchanges(null)
      }
    }
  }
}

/**
 * A concrete interceptor chain that carries the entire interceptor chain: all application
 * interceptors, the OkHttp core, all network interceptors, and finally the network caller.
 *
 * 一个具体的拦截器链,包含整个拦截器链:所有应用程序*拦截器,OkHttp核心,所有网络拦截器,最后是网络调用者。
 */
class RealInterceptorChain(...){
  @Throws(IOException::class)
  override fun proceed(request: Request): Response {
    ......

    calls++

    ......

    // Call the next interceptor in the chain.
    // 获取下一个拦截器
    val next = copy(index = index + 1, request = request)
    // 当前的拦截器
    val interceptor = interceptors[index]

    // 调用当前拦截器的 intercept 方法处理相关逻辑,并且将下一个拦截器传入,执行完成后返回 response
    @Suppress("USELESS_ELVIS")
    val response = interceptor.intercept(next) ?: throw NullPointerException(
        "interceptor $interceptor returned null")

    ......
    return response
  }
}

上面就是 okhttp 的核心所在了,将一个网络请求的各个逻辑拆分成一个个拦截器去处理,比如重试机制、缓存机制、网络连接等。下面来一张图可能就比较直观了,依据整个责任链条,逐步处理自己相应的逻辑,并最终依据链条,将结果逐步返回。

在这里插入图片描述

简易版OkHttp

下面是根据上面的逻辑,实现了一个大致的流程,是相当的粗糙。我觉得通过 150 行代码能梳理清除相关逻辑就可以了,不喜请喷

package com.silence.okhttpdemo.ok

import java.lang.Exception
import java.util.concurrent.SynchronousQueue
import java.util.concurrent.ThreadFactory
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit


/**
 * Author silence.
 * Time:2020/8/19.
 * Desc:简易版 okHttp,只为说明其大致流程
 */
object OK {
    private val okHttp = OkHttp()

    fun newCall(request: Request) = RealCall(okHttp,request)

    fun addInterceptor(interceptor: Interceptor){
        okHttp.interceptors.add(interceptor)
    }
}
class Request(val url:String,var header:String = "")

class Response{
    var isCache = false
    var url=""
    var header = ""
    var body = ""
    var result = ""
}

interface Callback {
    fun onResponse(response: Response)
}

class Dispatcher{
    private val executorService = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
        SynchronousQueue(), ThreadFactory { runnable ->
            Thread(runnable, "customer Thread")
        }
    )
    internal fun enqueue(call: RealCall.AsyncCall) {
        executorService.execute(call)
    }
}

class OkHttp {
    val dispatcher = Dispatcher()
    val cacheMgr = CacheMgr()
    val interceptors = mutableListOf<Interceptor>()
}

class RealCall(private val okHttp: OkHttp,
               private val request: Request){

    fun enqueue(responseCallback: Callback){
        okHttp.dispatcher.enqueue(AsyncCall(responseCallback))
    }

    fun enqueue() = getResponseWithInterceptorChain()

    internal fun getResponseWithInterceptorChain(): Response {
        val interceptors = mutableListOf<Interceptor>()
        interceptors += okHttp.interceptors
        interceptors += RetryAndFollowUpInterceptor()
        interceptors += CacheInterceptor(okHttp.cacheMgr)
        interceptors += CallServerInterceptor()
        val chain = RealInterceptorChain(interceptors,0,request)
        return chain.proceed(request)
    }

    internal inner class AsyncCall(private val responseCallback: Callback) :Runnable{
        override fun run() {
            responseCallback.onResponse(getResponseWithInterceptorChain())
        }
    }
}
interface Interceptor {
    fun intercept(chain: Chain): Response
    interface Chain {
        fun proceed(request: Request): Response
        fun request():Request
    }
}

class RealInterceptorChain(
    private val interceptors: List<Interceptor>,
    private val index: Int,
    private val request: Request
) : Interceptor.Chain{

    override fun proceed(request: Request): Response {
        val next = RealInterceptorChain(interceptors,index+1,request)
        val interceptor = interceptors[index]
        return interceptor.intercept(next)
    }

    override fun request() = request

}
class RetryAndFollowUpInterceptor : Interceptor{
    var retryCount = 0
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        while (true){
            try {
                return chain.proceed(request)
            } catch (e:Exception){
                retryCount++
            }
            if (retryCount > 3){
                val response = Response()
                response.result = "error"
                response.url = chain.request().url
                return response
            }
        }
    }
}
class CacheMgr{
    //这里肯定不能这么写昂,我这么写只是为了便于理解
    val cache = hashMapOf<String,Response>()
}
class CacheInterceptor(private val cacheMgr: CacheMgr) : Interceptor{

    override fun intercept(chain: Interceptor.Chain): Response {
        var response = cacheMgr.cache[chain.request().url]
        if (response == null){
            response = chain.proceed(chain.request())
            cacheMgr.cache[chain.request().url] = response
        } else {
            response.isCache = true
        }
        return response
    }
}
class CallServerInterceptor : Interceptor{
    //注意这里,作为最后一个 Interceptor,这里没有在调用 chain.proceed 方法了
    // 所以这里就是最底部了,从这里开始逐级向上返回 response
    override fun intercept(chain: Interceptor.Chain): Response {
        val response = Response()
        response.body = "body"
        response.header = chain.request().header
        response.result = "ok"
        response.url = chain.request().url
        return response
    }
}

在来康康怎么调用,基本上和 okHttp 调用方式差不多

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        OK.addInterceptor(object :Interceptor{
            override fun intercept(chain: Interceptor.Chain): Response {
                val request = chain.request()
                request.header = "customer header"
                return chain.proceed(request)
            }
        })

       OkHttpClient()
               .newCall(
                       Request.Builder()
                               .url("https://www.baidu.com")
                               .build()
               ).enqueue(
                       object : Callback {
                           override fun onFailure(call: Call, e: IOException) {

                           }
                           @Throws(IOException::class)
                           override fun onResponse(call: Call, response: Response) {
                           }
                       }
               )
    }

    fun asnyc(view: View) {
        OK.newCall(Request("https://www.baidu.com"))
            .enqueue(object :Callback{
                override fun onResponse(response: Response) {
                    Log.d("silence","url:${response.url} , result:${response.result} , header:${response.header} , isCache:${response.isCache} , body:${response.body}")
                }
            })
    }
    fun Synchronize(view: View) {
        thread {
            val response = OK.newCall(Request("https://www.baidu.com")).enqueue()
            Log.d("silence","url:${response.url} , result:${response.result} , header:${response.header} , isCache:${response.isCache} , body:${response.body}")
        }
    }
}

ok,到这基本上就大致理清整体思路了,上面没有说到的任何一个细枝末节都足以用一篇文章详细描述,太多了,还是自己去扒拉吧,read the fuck code,best wishes

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OkHttp是一个HTTP客户端库,它本身并不提供下拉刷新的功能,但可以与其他第三方库一起使用来实现下拉刷新。 一般情况下,下拉刷新需要结合RecyclerView或ListView等列表控件使用,可以使用开源库如SwipeRefreshLayout或SmartRefreshLayout实现下拉刷新。 例如,使用SwipeRefreshLayout实现下拉刷新的流程如下: 1. 在布局文件中添加SwipeRefreshLayout和RecyclerView控件: ``` <androidx.swiperefreshlayout.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout> ``` 2. 在Activity或Fragment中初始化SwipeRefreshLayout和RecyclerView,并设置下拉刷新监听器: ``` // 初始化SwipeRefreshLayout和RecyclerView SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout); RecyclerView recyclerView = findViewById(R.id.recycler_view); // 设置下拉刷新监听器 swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { // 执行下拉刷新操作 // 可以使用OkHttp发送网络请求获取最新数据 // 刷新完成后调用swipeRefreshLayout.setRefreshing(false)结束刷新 } }); ``` 3. 在下拉刷新操作完成后,调用swipeRefreshLayout.setRefreshing(false)方法结束刷新。 注意,OkHttp本身只是一个HTTP客户端库,它并不提供下拉刷新的功能,因此需要结合其他第三方库一起使用来实现下拉刷新。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值