current position:Home>Okhttp source code analysis of Android network framework

Okhttp source code analysis of Android network framework

2022-06-24 09:44:43Cattle within yards

okhttp Use

okhttp Is divided into Request Ask for something to do with response Respond to .

request Request body : every last HTTP Every request should contain a URL, One GET or POST Methods and Header Or other parameters , Of course, it can also contain data streams of specific content types .

response Response code : The response contains a reply code (200 On behalf of success ,404 The representative did not find ),Header And custom optional body.

Packaged okhttp Library and okhttp Use :

blog.csdn.net/xjz123456qq…

Basic request (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) {
               // Response failure 
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // Response successful 
            }
        });

POST

RequestBody body = RequestBody.create(JSON, jsonObject.toString());
 client.newCall(
                new Request.Builder()
                        .url(url)
                        //      .headers()// Add head 
                        .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 Request flow and source code analysis

From the above request, we can see that synchronous and asynchronous , It's all through newCall() To achieve the , that newCall() What has been achieved ?

// Returned a Call object 
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

Synchronization request call.execute()

override fun execute(): Response {
  // First judge whether you have requested 
  check(executed.compareAndSet(false, true)) { "Already Executed" }

  timeout.enter()
  callStart()
  try {
    // Distributor for distribution 
    client.dispatcher.executed(this)
    return getResponseWithInterceptorChain()//  Walking interceptor 
  } finally {
    client.dispatcher.finished(this)// Callback after completion 
  }
}

/** Used by [Call.execute] to signal it is in-flight. */
@Synchronized internal fun executed(call: RealCall) {
  runningSyncCalls.add(call)// Go directly to the running synchronization queue to get values 
}

Source code can be seen , Synchronous interceptor , Go directly to the executing synchronization queue to get the value .

Asynchronous requests

override fun enqueue(responseCallback: Callback) {
// First judge the current call Whether it has been implemented , Exception throwing was executed 
  check(executed.compareAndSet(false, true)) { "Already Executed" }

  callStart()
  client.dispatcher.enqueue(AsyncCall(responseCallback))// Asynchronous distribution 
}

internal fun enqueue(call: AsyncCall) {
  synchronized(this) {
    readyAsyncCalls.add(call)// First put the task in the waiting queue 

    // 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()
    // Iterations wait to execute asynchronous requests 
    while (i.hasNext()) {
      val asyncCall = i.next()
      // Number of tasks executing asynchronous requests   Not greater than  64 individual 
      if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
      // The same host Number of requests for   Not greater than 5
      if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.

      i.remove()
      asyncCall.callsPerHost.incrementAndGet()
      executableCalls.add(asyncCall)  // A collection of tasks that need to be started , Create a temporary queue 
      runningAsyncCalls.add(asyncCall)// Put the task to be executed into the queue that is executing asynchronously 
    }
    isRunning = runningCallsCount() > 0
  }

  // Process the tasks in the temporary queue , Iterative processing 
  for (i in 0 until executableCalls.size) {
    val asyncCall = executableCalls[i]
    asyncCall.executeOn(executorService)// Put it into the thread pool for processing 
  }

  return isRunning
}

// Asynchronous processing task source code 
override fun run() {
  threadName("OkHttp ${redactedUrl()}") {
    var signalledCallback = false
    timeout.enter()
    try {
      //  Perform the requested , Walking interceptor 
      val response = getResponseWithInterceptorChain()
      signalledCallback = true
      responseCallback.onResponse([email protected], 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([email protected], e)
      }
    } catch (t: Throwable) {
      cancel()
      if (!signalledCallback) {
        val canceledException = IOException("canceled due to $t")
        canceledException.addSuppressed(t)
        responseCallback.onFailure([email protected], canceledException)
      }
      throw t
    } finally {
      client.dispatcher.finished(this)// Callback after completion 
    }
  }
}

/** 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()// After completing this mission request , To make the next request 

  if (!isRunning && idleCallback != null) {
    idleCallback.run()
  }
}

As can be seen above ,RealCall There are three queues in the

1、 Executing synchronization queue
2、 Executing asynchronous queue
3、 Asynchronous queue ready for execution , A queue in which tasks are queued for preparation

Asynchronous request process :

1、enqueue() after , First judge whether the current task is executed , Distribution without distributor is not executed
2、 First put the task into the asynchronous queue waiting for execution readyAsyncCalls in
3、 Perform an iteration on the waiting queue , Judge whether the number of tasks being executed is greater than 64 , same host Is it greater than 5
4、 The number of tasks in the executing asynchronous queue is greater than 64, It cannot be executed , Continue waiting in the waiting queue , If the current mission is host>5, Then judge the execution of the next task
5、 Put the task to be executed into the task being executed , And put it in a temporary alignment , Call the thread pool to execute
6、 After thread pool execution , Walking interceptor , After completion , Let's go .
7、 The interceptor follows the chain of responsibility mode , The five interceptors execute , After completion , Callback .
8、 After completion , Re trigger promoteAndExecute(), Make the next task request

Five interceptors

1、RetryAndFolloeUpInterceptor: Retry the directional interceptor

Determine whether the user canceled the interceptor , After obtaining the results , Use the status code to determine whether redirection is needed , Restart all interceptors if conditions are met

2、BrisgeInterceptor: Bridge interceptor

Network processing after parameter transmission :Header, Body Handle , Automatically put HTTP agreement , Request header ,,GZIP Compress , Wait for the treatment , preservation cookie Interface to handle

3、CacheInterceptor: Cache interceptor

Request a resource that will not change , Before reading, judge whether there is a current cache , If there is a cache, call the cache and call back directly , No, , Take the connection interceptor

4、Connection: Connection interceptor

Cache miss , Take the connection interceptor , Find the connection to the server , Or create a connection , Get the corresponding socket flow , No additional processing after obtaining the results , Go straight to the request service interceptor

5、CallServerInterceptor: Request service interceptor

When you get the connector , Package data in class Send it to the server , Get a response , Communicate with the server , Send data to the server , Parse the response data read , Go back step by step

The chain of responsibility model

Similar to recursive call , From top to bottom , After execution , The result returns from bottom to top .

Finally, in order to help everyone learn effectively Android Top 100 framework knowledge points , Specially arranged a Android 100 frames for advanced urination , Help everyone further on the road of Technology , There's something you need You can reply to me by private mail in the background 666 Ready to pick up !!!

copyright notice
author[Cattle within yards],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/175/202206240822498385.html

Random recommended