Okhttp 01 核心流程详解

OkHttp核心机制深度剖析:拦截器、连接池与缓存策略 在Android应用开发中,网络通信是核心环节,而HTTP协议的性能优化往往决定用户体验。连接池负责复用TCP连接,减少握手开销;缓存机制通过HTTP缓存协议避免重复请求。OkHttp作为业界成熟的HTTP客户端,将连接管理、拦截器链、协议适配等能力整合起来。理解其责任链设计,可以灵活扩展网络逻辑;掌握其连接池和缓存策略,能有效提升弱网环境下的稳定性。从基础概念到工程实践,剖析OkHttp的核心机制,有助于开发者构建高性能、可靠的网络层。 阅读详情
1.dns解析,域名对应 ip
2.TCP建立连接,三次握手
3.C端向S端发送请求行命令
4.C端发送请求头信息
5.S端应答,发送响应命令
6.S端发送响应头信息
7.S端向C端发送数据,以及消息体
8.S端关闭链接 tcp 四次挥手

An HTTP client for Android, Kotlin, and Java.

https://square.github.io/okhttp/
源码
https://github.com/square/okhttp

参考:
hencoder plus
https://juejin.im/post/5d6e7f256fb9a06ae57d0d9c
4.x
OkHttp works on Android 5.0+ (API level 21+) and on Java 8+.

The OkHttp 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+.
These platforms lack support for TLS 1.2 and should not be used.
But because upgrading is difficult we will backport critical fixes to the 3.12.x branch through December 31, 2020.

一个简单请求 okhttp 做了什么

  1. 创建⼀个 OkHttp 的实例
    OkHttpClient client = new OkHttpClient.Builder().build();

  2. 创建 Request
    Request request = new Request.Builder()
    .url(“http://hencoder.com”)
    .build();

  3. 创建 Call 并发起⽹络请求

Call call = client.newCall(request);
@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}
client.newCall(request).enqueue(new Callback() {

@Override 
public void onFailure(Call call, IOException e) {}

@Override public void onResponse(Call call, Response response) throws IOException{
Log.d("okhttp response", response.body().string());}
});

可以看到,使用okhttp发起网络请求要经过4步:

  1. 创建OkHttpClient
  2. 创建请求Request
  3. 通过OkHttpClient和Request创建一个Call,用于发起网络请求
  4. 调用Call的execute()或enqueue()方法发起同步或异步请求

本次分析的okhttp源码版本是基本3.14.x

小结

okhttp的异步请求过程分析总结

  • 当我们调用call.enqueue(Callback)时,就会发起一个异步请求,
  • 实际执行的是realCall.enqueue(Callback),它比同步请求只是多了一个Callback参数,
  • 然后realCall.execute()中先把传进来的Callback包装成一个AsyncCall,
  • 然后执行Dispatcher的enqueue(AsyncCall)把这个异步请求任务保存进readyAsyncCalls队列中,
  • 保存后开始执行 promoteAndExecute()进行异步任务的调度,
  • 它会先把符合条件的异步请求任务从readyAsyncCalls转移到runningAsyncCalls队列和添加到executableCalls列表中去,
  • 然后遍历executableCalls列表,逐个执行AsyncCall 的executeOn(ExecutorService),
  • 然后在这个方法中AsyncCall会把自己放进Dispatcher 的线程池,等待线程池的调度
  • 当线程池执行到这个AsyncCall时,它的run方法就会被执行,从而执行重写的execute()方法,execute()方法中的流程和同步请求流程大致相同。

下面是异步请求过程的调用链:

整个流程

  1. okhttp通过Builder模式创建OkHttpClient、Request和Response,
  2. 通过client.newCall(Resquest)创建一个Call,用于发起异步或同步请求
  3. 请求会经过Dispatcher、一系列拦截器,最后通过okio与服务器建立连接、发送数据并解析返回结果
    这个过程如图:

1、创建OkHttpClient

OkHttpClient是okhttp中的大管家,它将具体的工作分发到各个子系统中去完成,它使用Builder模式配置网络请求的各种参数如超时、拦截器、分发器等,Builder中可配置的参数如下:
builder 模式是,先赋值正确,在创建对象。set 是先给予默认值,然后修改。

//OkHttpClient.Builder
public static final class Builder {
    Dispatcher dispatcher;//分发器
    @Nullable Proxy proxy;//代理
    List<Protocol> protocols;//应用层协议
    List<ConnectionSpec> connectionSpecs;//传输层协议
    final List<Interceptor> interceptors = new ArrayList<>();//应用拦截器
    final List<Interceptor> networkInterceptors = new ArrayList<>();//网络拦截器
    EventListener.Factory eventListenerFactory;//http请求回调监听
    ProxySelector proxySelector;//代理选择
    CookieJar cookieJar;//cookie
    @Nullable Cache cache;//网络缓存
    @Nullable InternalCache internalCache;//内部缓存
    SocketFactory socketFactory;//socket 工厂
    @Nullable SSLSocketFactory sslSocketFactory;//安全套接层socket 工厂,用于HTTPS
    @Nullable CertificateChainCleaner certificateChainCleaner;//验证确认响应证书,适用 HTTPS 请求连接的主机名
    HostnameVerifier hostnameVerifier;//主机名字确认
    CertificatePinner certificatePinner;//证书链
    Authenticator proxyAuthenticator;//代理身份验证
    Authenticator authenticator;//本地身份验证
    ConnectionPool connectionPool;//连接池,复用连接
    Dns dns;//域名
    boolean followSslRedirects;//安全套接层重定向
    boolean followRedirects;//本地重定向
    boolean retryOnConnectionFailure;//错误重连
    int callTimeout;//请求超时,它包括dns解析、connect、read、write和服务器处理的时间
    int connectTimeout;//connect超时
    int readTimeout;//read超时
    int writeTimeout;//write超时
    int pingInterval;//ping超时

    //这里是配置默认的参数
    public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;//Protocol.HTTP_2和Protocol.HTTP_1_1
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      if (proxySelector == null) {
        proxySelector = new NullProxySelector();
      }
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;
      callTimeout = 0;
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
      pingInterval = 0;
    }

    //这里通过另外一个OkHttpClient配置参数
    Builder(OkHttpClient okHttpClient) {
      this.dispatcher = okHttpClient.dispatcher;
      this.proxy = okHttpClient.proxy;
      this.protocols = okHttpClient.protocols;
      //...
    }
    
    //...
    
    //配置完参数后,通过Builder的参数创建一个OkHttpClient
    public OkHttpClient build() {
        return new OkHttpClient(this);
    }
}

2、创建请求Request

在 okhttp 中 Request 代表着一个HTTP请求,它封装了请求的具体消息,如url、header、body等,它和OkHttpClient一样都是使用Budiler模式来配置自己的参数,如下:

//Request.Budiler
public static class Builder {
    HttpUrl url;
    String method;
    Headers.Builder headers;
    RequestBody body;

    //这里配置默认的参数
    public Builder() {
      this.method = "GET";//默认是GET请求
      this.headers = new Headers.Builder();
    }

    //这里通过另外一个Request配置参数
    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      //...
    }
    
    //...
    
    //配置完参数后,通过Builder的参数创建一个Request
    public Request build() {
        if (url == null) throw new IllegalStateException("url == null");
        return new Request(this);
    }
}

3、创建用于发起网络请求的Call

Call是一个接口,它的具体实现类是RealCall,Call中定义了一些enqueue(Callback)、execute()等关键方法,如下:
调用**client.newCall(request)**其实返回的是RealCall对象,而RealCall封装了请求的调用逻辑。

public interface Call extends Cloneable {
    //返回当前请求
    Request request();
    //同步请求方法,此方法会阻塞当前线程直到请求结果放回
    Response execute() throws IOException;
    //异步请求方法,此方法会将请求添加到队列中,然后等待请求返回
    void enqueue(Callback responseCallback);
    //取消请求
    void cancel();
	//判断请求是否在执行
    boolean isExecuted();
    //判断请求是否取消
    boolean isCanceled();
    //返回请求的超时时间
    Timeout timeout();
    //克隆一个新的请求
    Call clone();
    interface Factory {
        Call newCall(Request request);
    }
}


public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
    //...
    @Override 
    public Call newCall(Request request) {
        //调用了RealCall的newRealCall()
        return RealCall.newRealCall(this, request, false /* for web socket */);
    }
}

final class RealCall implements Call {
    //...
    static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) 	{
        //返回RealCall对象
        RealCall call = new RealCall(client, originalRequest, forWebSocket);
        call.transmitter = new Transmitter(client, call);
        return call;
    }
}



同步请求 - RealCall :: execute()
//RealCall.java
@Override
public Response execute() throws IOException {
    //...
    try {
        //1、调用Dispatcher的executed(RealCall)方法
        client.dispatcher().executed(this);
        //2、调用getResponseWithInterceptorChain()方法
        return getResponseWithInterceptorChain();
    } finally {
        //3、同步请求任务执行完毕,调用Dispatcher的finished(RealCall)方法
        client.dispatcher().finished(this);
    }
}
client就是我们上面所讲的OkHttpClient的实例,它在创建RealCall时作为构造参数传了进去,而OkHttpClient的dispatcher()方法返回的是Dispatcher实例,
它在OkHttpClient构造时被创建。
Dispatcher是一个任务调度器
它负责进行请求任务的调度,它的内部维护着3个任务队列(readyAsyncCalls、runningAsyncCalls、runningSyncCalls)和1个线程池(executorService),Dispatcher主要内容如下:
public final class Dispatcher {
    private int maxRequests = 64;//最大请求数64个
    private int maxRequestsPerHost = 5;//每个主机最大请求数5个
    private @Nullable Runnable idleCallback;//idle任务回调,类似于Android的idlehandler, 可以在Dispatcher没有任务调度(空闲时)时执行idleCallback中的任务

    //线程池,执行runningAsyncCalls队列里面的请求任务
    private @Nullable ExecutorService executorService;

    //等待执行的异步请求任务队列
    private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    //正在执行的异步请求任务队列
    private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    //正在执行的同步请求任务队列
    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

    synchronized void executed(RealCall call) {
        //...
    }

    void enqueue(AsyncCall call) {
        //...
    }  
    
    void finished(RealCall call) {
        //...
    }

    void finished(AsyncCall call) {
        //...
    }
    
    private boolean promoteAndExecute() {
        //...
    }

  //...  
}
  • Dispatcher提供了
    executed(RealCall)和enqueue(AsyncCall)方法来进行同步和异步请求任务的入队,
  • 还提供了finished(RealCall)和finished(AsyncCalll)方法来进行同步和异步请求任务的出队
  //Dispatcher
  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

可以看到okhttp把ReadCall当作同步请求任务的代表,把AsyncCall当作异步请求任务的代表,

  1. RealCall前面已经讲过了,而AsyncCal是RealCall的一个内部类,它本质上就是一个Runnable,
  2. Dispatcher的线程池执行任务主要执行的是 runningAsyncCalls 队列里面的异步请求任务,
    也就是AsyncCall异步任务
  3. 而Dispatcher的promoteAndExecute()方法就是用来进行异步任务的调度,它的逻辑主要是按顺序把readyAsyncCalls队列中准备执行的异步任务转移到runningAsyncCalls后,
    再由线程池执行,对于同步任务 Dispatcher只是暂时保存在runningSyncCalls队列中,并不会由线程池执行。

同步执行:

1. Dispatcher :: executed(RealCall)

看RealCall的execute()方法,
它首先调用了Dispatcher的executed(RealCall)方法
,Dispatcher的executed(RealCall)方法实现如下:

//Dispatcher.java
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}

可以看到没有做什么处理,只是简单的把同步请求任务放入runningSyncCalls队列。

2. RealCall :: getResponseWithInterceptorChain()

看RealCall的execute(),调用getResponseWithInterceptorChain()方法,这里才是同步请求处理的地方,我们点进去,如下:


//RealCall.java 
Response getResponseWithInterceptorChain() throws IOException {
    //拦截器的添加
    List<Interceptor> interceptors = new ArrayList<>();
    //添加用户自定义拦截器
    interceptors.addAll(client.interceptors());
    //添加默认拦截器
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    //添加的最后一个拦截器是CallServerInterceptor
    interceptors.add(new CallServerInterceptor(forWebSocket));

    //创建一个RealInterceptorChain,传入了interceptors和Request
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    try {
      //调用RealInterceptorChain的proceed(Request)方法处理请求
      Response response = chain.proceed(originalRequest);
      //...
      return response;
    } catch (IOException e) {
     //...
    } finally {
     //...
    }
  }

3. Dispatcher :: finished(RealCall)

我们继续看RealCall的execute()方法,调用Dispatcher的finished(AsyncCall)方法,如下:

//Dispatcher.java
void finished(RealCall call) {
    //传进了runningSyncCalls队列
    finished(runningSyncCalls, call);
}

private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
        //尝试移除队列中的同步请求任务
        if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
        idleCallback = this.idleCallback;
    }

    //紧接着调用promoteAndExecute()方法进行异步任务的调度,如果没有异步任务要进行,promoteAndExecute()返回false
    boolean isRunning = promoteAndExecute();

    //isRunning等于false且设置了idleCallback,会执行一遍idle任务
    if (!isRunning && idleCallback != null) {
        idleCallback.run();
    }
}
  • finished()方法中首先尝试从runningSyncCalls队列把刚才通过 executed()入队的同步任务RealCall移除
  • 如果移除失败,就抛出异常
  • 如果移除成功,就紧接着调用promoteAndExecute()方法进行异步任务的调度并尝试执行一遍idle任务,promoteAndExecute()方法在异步请求中再详细介绍。

小结

至此okhttp的同步请求过程分析完毕,这里总结一下:

  1. 当我们调用call.execute()时,就会发起一个同步请求,
  2. 而call的实现类是RealCall,所以实际执行的是realCall.execute(),
  3. realCall.execute()中执行Dispatcher的executed(RealCall)把这个同步请求任务保存进runningSyncCalls队列中,(没有做事情,只是入队出队。)
  4. 然后RealCall执行getResponseWithInterceptorChain()处理同步请求,
  5. 请求经过层层拦截器后到达最后一个拦截器CallServerInterceptor,在这个拦截器中通过Exchange把请求发送到服务器,
  6. 然后同样的通过Exchange获得服务器的响应,根据响应构造Response,然后返回,
  7. 最后RealCall执行Dispatcher的finished(RealCall)把之前暂时保存的同步请求任务从runningSyncCalls队列中移除。

下面是同步请求过程的调用链:

异步请求 - RealCall.enqueue(Callback)

//RealCall.java
@Override
public void enqueue(Callback responseCallback) {
    //...
    //1、调用Dispatcher的enqueue(AsyncCall)方法
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

它比同步请求只是多了一个Callback,

在Callback的 onResponse(Call, Response)回调中我们可以拿到网络响应返回的Response,
RealCall的enqueue(Callback)方法中首先把Callback用AsyncCall包装起来,
然后调用调用Dispatcher的enqueue(AsyncCall)方法。

1. Dispatcher :: enqueue(AsyncCall)

我们看Dispatcher的enqueue(AsyncCall)方法,如下:

//Dispatcher.java
void enqueue(AsyncCall call) {
    synchronized (this) {
       readyAsyncCalls.add(call);
       //...
    }
    promoteAndExecute();
}

2. Dispatcher :: promoteAndExecute()

//Dispatcher.java
private boolean promoteAndExecute() {
    //准备一个正在执行任务列表executableCalls
    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
        //1、这个for循环主要把readyAsyncCalls中等待执行的异步任务转移到runningAsyncCalls队列和executableCalls列表中去
        for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {

            //取出readyAsyncCalls中等待执行的异步任务
            AsyncCall asyncCall = i.next();

            //判断条件:1、正在运行的异步请求任务不能大于maxRequests;2、等待执行的异步任务的主机请求数不能大于maxRequestsPerHost
            if (runningAsyncCalls.size() >= maxRequests) break; 
            if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue;
            //满足条件,进入下面逻辑

            //把这个等待执行的异步任务从readyAsyncCalls中移除
            i.remove();
            asyncCall.callsPerHost().incrementAndGet();
            
            //把这个等待执行的异步任务添加进executableCalls列表
            executableCalls.add(asyncCall);
            //把这个等待执行的异步任务添加进runningAsyncCalls队列
            runningAsyncCalls.add(asyncCall);
        }
        
        //runningCallsCount()里面的逻辑: return runningAsyncCalls.size() + runningSyncCalls.size();
        isRunning = runningCallsCount() > 0;
    }
    //2、这个for循环主要是执行executableCalls列表中的异步任务
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
        AsyncCall asyncCall = executableCalls.get(i);
        //传进executorService,调用AsyncCall的executeOn()方法,由线程池执行这个异步任务
        asyncCall.executeOn(executorService());
    }

    return isRunning;
}


promoteAndExecute()方法中主要是2个for循环,

  • 第 1 个for循环是把符合条件的异步请求任务从readyAsyncCalls转移(提升)到runningAsyncCalls队列和添加到executableCalls列表中去,
  • 第 2 个for循环就是遍历executableCalls列表,从executableCalls列表中获取AsyncCall对象,并且调用它的executeOn()方法,
  • executeOn()方法传进了一个Dispatcher的executorService,所以我们看AsyncCall的executeOn()方法,里面是真正执行异步请求任务的地方。

3. 1、AsyncCall :: executeOn(ExecutorService)

AsyncCall的executeOn()方法如下:

//AsyncCall.java
void executeOn(ExecutorService executorService) {
    boolean success = false;
    try {
        //传进this,执行AsyncCall异步任务,AsyncCall本质是Runnable
        executorService.execute(this);
        success = true;
    } catch (RejectedExecutionException e) {
       //...
    } finally {
        if (!success) {
            //异步任务执行失败,调用Dispatcher的finished(AsyncCall)方法
            client.dispatcher().finished(this); 
        }
    }

主要逻辑就是调用
executorService.execute(this)执行当前的 AsyncCall 异步任务,
AsyncCall实现了NamedRunnable,本质是Runnable,如下:

final class AsyncCall extends NamedRunnable {
    //...
}

public abstract class NamedRunnable implements Runnable {
	//...	
  @Override
    public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      //run方法中执行execute()方法
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

AsyncCall实现了NamedRunnable,所以AsyncCall重写了execute()实现了执行逻辑,所以我们直接看AsyncCal的execute()方法。

4. 2、AsyncCall :: execute()

AsyncCal的execute()方法如下:
//AsyncCall.java
@Override 
protected void execute() {
    //...
    try {
        //调用RealCall的getResponseWithInterceptorChain()方法处理请求
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        //请求处理完毕,返回响应,回调Callback的onResponse()方法
        responseCallback.onResponse(RealCall.this, response);
    } catch (IOException e) {
        //...
    } finally {
        //异步请求任务执行完毕,调用Dispatcher的finished(AsyncCall)方法
        client.dispatcher().finished(this);
    }
}

AsyncCal的execute()方法的逻辑和前面介绍的同步请求过程殊途同归,

  1. 首先调用RealCall的getResponseWithInterceptorChain()方法处理请求
  2. 请求处理完毕后,返回响应Response,
  3. 这时回调我们调用Call.enqueue(Callback)时传进来的Callback的onResponse()方法,
  4. 最后在finally语句中调用Dispatcher的finished(AsyncCall)方法来把异步请求任务从runningAsyncCalls队列中移除出去,
  5. 这个移除逻辑和上面同步请求任务的移除逻辑一样,只是这次是从runningAsyncCalls移除而不是runningSyncCalls.
01.OkHttp基本用法 目录介绍 01.OkHttp简单介绍 02.OkHttp简单使用 03.OkHttp的流程图 01.OkHttp简单介绍 1.支持HTTP2/SPDY 2.socket自动选择最好路线,并支持自动重连 3.拥有自动维护的socket连接池,减少握手次数 4.拥有队列线程池,轻松写并发 5.拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩)基于Headers的缓存策略 0... 阅读详情

相关推荐

05.OkHttp线程池

目录介绍 01.线程池的理解 02.Dispatcher类详解 03.OKHttp的任务调度 04.OKHttp调度优雅之处 01.线程池的理解 android中的异步任务 android的异步任务一般都是用Thread+Handler或者AsyncTask来实现,其中笔者当初经历过各种各样坑,特别是内存泄漏,当初笔者可是相当的欲死欲仙啊!所以现在很少有开发者还在用这一套来做异步任务,现在...

杨充 4323

OkHttp3.x解析(一) OkHttp介绍以及基本使用

OkHttp是一个目前流行高效的HTTP客户端: HTTP/2支持允许对同一主机的所有请求共享一个套接字。 连接池减少了请求延迟(如果HTTP/2不可用)。 透明的GZIP压缩了下载文件的大小。 响应缓存完全避免了网络中的重复请求。 当网络出现问题的时候OkHttp依然坚守自己的职责,当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当...

倚栏静望的博客 835

Workbench-nCode下发动机引擎应力疲劳分析

在工程数据库中定义材料模型参数,结构场分析基本参数:密度7850Kg/m3、弹性模量210E9Pa、泊松比0.3,疲劳分析参数:应力-疲劳曲线表(S-N Curve),应力-疲劳曲线如下图2所示,如果没有合适的数据可使用结构钢材料进行分析。网格为四面体高阶单元,各零件的单元尺寸如下表1所示,单元质量分布如下图3所示。在workbench平台下搭建分析流程如下图6所示,前述设定完成后,提交求解后即可得到相应的应力、应变结果,更新结果后目录树中会有相应的nCode DesignLife插件,如下图7所示。

ansysxuexizhe的博客 1547

OKHttp使用详解

一,OKHttp介绍okhttp是一个第三方类库,用于android中请求网络。这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient(android API23 里已移除HttpClient)。okhttp有自己的官网,官网网址:OKHttp

fightingXia的博客 9万+

告别版本过低提示!微信3.9登录修复与聊天记录无缝迁移全攻略

本文详细解析了微信3.9版本过低提示的根源,并提供了完整的修复方案和聊天记录迁移指南。通过专用修复工具绕过版本检测,以及新旧版本聊天记录目录对比,帮助用户实现无缝迁移。特别提醒备份重要数据,确保操作安全。

weixin_42535461的博客 3127

计算机组成原理实验(已通关)-华中科技大学头歌Educoder(Logisim)

汉字国标码转区位码实验 汉字机内码获取实验 8位可控加减法电路设计 第2关 CLA182四位先行进位电路设计 第3关 4位快速加法器设计 第4关 16位快速加法器设计 第5关 32位快速加法器设计 第6关 5位无符号阵列乘法器设计 6位有符号补码阵列乘法器 乘法流水线设计 原码一位乘法器设计 偶校验编码设计 偶校验解码电路设计 16位海明编码电路设计 16位海明解码电路设计 海明编码流水传输实验 16位CRC并行编解码电路设计 CRC编码流水传输实验

紫荆鱼的博客 4万+

OkHttp内部流程解析

最近在看okhttp源码,这个流程度总结的很棒,记录一下~

weixin_38251977的博客 291

避坑指南:麒麟系统ARM架构下PostGIS离线安装常见问题解析

本文深度解析了在国产麒麟系统ARM64架构下进行PostGIS离线安装的完整路径与核心避坑点。通过对比Docker容器化与源码编译两种部署方式的优劣,详细阐述了离线Docker环境搭建、ARM64镜像获取验证、容器化配置及常见故障排查的全流程,为在特殊环境下稳定部署空间数据库提供了一套可靠的实践指南。

Python的专栏 287

OkHttp 3,应届生面试销售岗位的面试问题技巧

从上面可以看出涉及Dispatcher的两个关键方法:enqueue(AsyncCall)和promoteAndExecute()。下面就分别来分析这两个方法。方法:enqueue(AsyncCall)enqueue方法还没有对AsyncCall进行真正的资源分配和调度,只是对AsyncCall进行一些设置,真正的调度逻辑是由后面的promoteAndExecute()方法实现。我们先来简单看一下enqueue方法的流程:接着我们分析一下代码://第一步:添加AsyncCall到预执行队列。

2401_84170623的博客 719

从零构建:基于OpenCV与人体姿态分析的跌倒检测实战(附完整源码)

本文详细介绍了如何从零构建基于OpenCV与人体姿态分析的跌倒检测系统,包含完整源码与部署指南。通过MediaPipe实时检测33个人体关键点,结合多条件联合判断算法,实现高精度跌倒识别。文章还提供了性能优化技巧、常见问题解决方案以及家用与养老院两种部署方案,帮助开发者快速落地这一计算机视觉应用。

weixin_29085151的博客 240

DDR内存接口深度解析:从寻址机制到FPGA时序约束实战

在高速数字系统设计中,内存接口是决定系统性能与稳定性的关键。DDR(双倍数据速率)技术通过在时钟的上升沿和下降沿传输数据,实现了带宽的倍增,广泛应用于消费电子、通信设备和工控主板等领域。其核心原理在于利用三维存储阵列(Bank、Row、Column)的分级寻址机制,通过先进行行激活、再进行列访问的固定时序,实现高速数据吞吐。理解这一寻址顺序是进行精准时序分析的基础。在工程实践中,FPGA作为内存控制器,需通过严谨的时序约束(如set_input_delay)来确保信号在高速传输下的建立与保持时间要求,从而将

weixin_29192211的博客 196

01-04-02 OkHttp核心完全指南

本文深入解析OkHttp核心机制,涵盖连接复用、拦截器链、缓存策略等关键特性。作为Android主流HTTP客户端,OkHttp支持HTTP/2、透明GZIP、WebSocket等功能。文章详细介绍了基础配置方法,包括超时设置、连接池优化,并提供了同步/异步请求的代码示例。针对企业级应用场景,重点讲解了如何通过拦截器实现日志记录、Token认证等扩展功能。通过25+实战案例,帮助开发者掌握OkHttp的高级用法,优化网络性能与安全性。

时代我西的博客 197

多源异构数据融合(Kaggle+Google Trends联合分析)

本文详细介绍了如何利用Python实现多源异构数据融合,以Kaggle电商销售数据与Google Trends搜索指数为例,展示了数据清洗、预处理、时间对齐、数据合并、相关性分析、回归建模和可视化全过程。数据预处理与内存优化通过分块加载、数据类型转换和缺失值处理,有效降低了大规模数据在内存中的占用,并确保数据质量。时间对齐与数据融合策略采用重采样与内连接方法对齐不同数据源的时间维度,实现了高质量数据的融合,为后续联合分析奠定基础。模型构建与分析。

闲人编程的博客 1015

OKHttp源码解析

Android4.4之后系统的HttpUrlConnection的实现是基于okhttp实现的。 Android各版本引用的对应okhttp版本: Android 4.4.4_r1:     OKHttp 1.1.2 Android 5.0.1_r1:     OKHttp 2.0.0 Android 6.0.1_r1:     OKHttp 2.4.0 An...

JackWangDev的博客 249

ROSTEA软件下载及情感分析详细操作教程(附网盘链接)

原ROST虚拟团队出品的ROST系列文本内容挖掘分析平台,是辅助人文社会科学研究的免费计算平台。该软件可以实现文本预处理、分字、分词、词性识别、特殊名词抽取、词频统计、英文词频统计、情感计算、分类算法、聚类算法等一系列文本挖掘,是人文社科研究和论文写作的一把利器。该软件用户量超过一万人,遍布海内外100多所大学,包括剑桥大学、日本北海道大学、北京大学、清华大学、香港城市大学、澳门大学等众多高校。关于ROSTCM6的安装介绍可以参考之前的文章ROSTCM6软件下载及语义网络分析详细操作教程ROST EA。

m0_64336780的博客 1万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

OKHttp源码解析(一) OkHttp整体流程

OkHttp官网地址:http://square.github.io/okhttp/ OkHttp GitHub地址:https://github.com/square/okhttp 本篇文章阐述一下OKHttp的整体流程。首先通过代码来一步一步进行分析它的内部流程。 源码环境 OKHttp3.2.0 1,基本用法 1.1,创建 OkHttpClient 对象 final

ostracod 1375

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

安卓库移植鸿蒙实战——以okhttp为例详解适配过程

本文详细介绍了如何将安卓库okhttp移植到鸿蒙系统的实战过程,包括开发环境配置、项目结构改造、核心代码适配方案及常见问题解决方案。通过替换Socket层、改造异步回调和适配证书验证,成功实现了okhttp在鸿蒙环境下的稳定运行,并提供了完整示例项目供参考。

weixin_30566063的博客 422

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

OKHTTP原理

设计模式: Builder、责任链 (1)、当我们通过OkhttpClient创建一个Call,并发起同步或异步请求时; (2)、okhttp会通过Dispatcher对我们所有的RealCall(Call的具体实现类)进行统一管理,并通过execute()及enqueue()方法对同步或异步请求进行处理; (3)、execute()及enqueue()这两个方法会最终调用RealCall中的ge...

生活,需要你的温暖。 533

01-10-17 OkHttp源码完全解析

摘要 本文深入解析OkHttp 4.x源码,揭示其高效网络请求的实现机制。OkHttp采用责任链模式的拦截器架构,包含5个核心拦截器:重试拦截器、桥接拦截器、缓存拦截器、连接拦截器和请求服务拦截器。通过连接池实现TCP连接复用,利用DiskLruCache实现响应缓存,支持HTTP/2协议。源码分析表明,OkHttp通过分层设计和模块化组件,在保证灵活性的同时实现了高性能网络通信。其拦截器链设计允许开发者自定义处理逻辑,而连接池机制则显著提升了网络请求效率。 关键词:OkHttp、拦截器链、连接池、缓存机制

时代我西的博客 38

Okhttp之五种拦截器

是整个责任链中的第一个,是首次接触到Request与最后接收到 Response的,主要功能就是判断是否需要重试与重定向。重试的前提是出现了 RouteException 或IOException。一旦在后续的拦截器执行过程中出现这两个异常,就会通过 recover 方法进行判断是否进行连接重试。重定向发生在重试的判定之后,如不满足重试的条件,还需要进一步调用 followUpRequest 根据Response 的响应码(如果直接请求失败, Response都不存在就会抛出异常)。

追梦的鱼儿 7129

OkHttp框架入门笔记

本文讲解了我对Android开发现状的一些看法,也许有些人会觉得我的观点不对,但我认为没有绝对的对与错,一切交给时间去证明吧!愿与各位坚守的同胞们互相学习,共同进步!《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!结本文讲解了我对Android开发现状的一些看法,也许有些人会觉得我的观点不对,但我认为没有绝对的对与错,一切交给时间去证明吧!愿与各位坚守的同胞们互相学习,共同进步!

2401_84132589的博客 888

Android OKHttp缓存模块原理分析

OkHttp 的缓存模块实现了完整的 HTTP 缓存机制,包括强缓存和协商缓存。自动缓存管理:OkHttp 会自动根据 HTTP 响应头中的缓存指令,管理缓存的存储和使用。开发者无需手动处理缓存的过期时间、验证等问题,只需要配置好缓存目录和大小即可。支持多种缓存策略:OkHttp 支持字段中的各种指令,如max-ageno-cacheno-store等,能够满足不同场景下的缓存需求。高效的缓存存储。

Android开发领域创作者 1024

Android面试之Okhttp的一些八股文

本文使用的okhttp版本是4.12.0。

weixin_42687841的博客 1186

OkHttp基础用法

OKHttp的基础用法 准备工作 核心代码 第一章 准备工作 第01节 资源库的准备 1、位置 在 build.gradle 当中的 dependencies 里面导入 okhttp 的操作。 2、代码 implementation 'com.squareup.okhttp3:okhttp:4.9.0' 第02节 清单文件权限 1、位置 在 manifests 清单文件当中的 AndroidManifest.xml 当中引入网络权限 2、代码 <!-- 导入网络权限 -->

浪客川 755

picasso2-okhttp3-downloader完全指南:从入门到精通的Android图片加载秘籍

picasso2-okhttp3-downloader是一款为Picasso 2打造的OkHttp 3下载器实现,专为Android开发者提供高效稳定的图片加载解决方案。本指南将带你全面掌握这个工具的使用方法和最佳实践,让你的应用图片加载体验更上一层楼。 ## 🚀 为什么选择picasso2-okhttp3-downloader? 在Android开发中,图片加载是一个常见且重要的任务。Pi

gitblog_00528的博客 414

[ 转载 ] Okhttp的用法

Android中OkHttp的使用 LuckyXiang 简书作者 02018-01-18 19:04 打开App Android中OkHttp的使用 官方网站 | Javadoc 1 简介 OkHttp是Square出的Http通讯库,支持HTTP和HTTP/2,用于Android应用和Java应用。 OkHttp是非常优秀的Http通讯库...

weixin_30549657的博客 130
上一篇: Android事件分发机制详解
下一篇: Android UID 问题 uid 改变进行了覆盖安装
阿杰、
博客等级 码龄11年 13粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值