OkHttp基本使用和内部基本原理

Okhttp是什么

Okhttp是Java上很流行的一款网络情况框架,由square出品

基本使用

 		String url = "http://co-api.51wnl.com//Calendar/GetStar?starName=aries&client=ceshi&token=7AFA7AC511153E696C09D04F94816CB1";
        Request request = new Builder().url(url).build();
        OkHttpClient okHttpClient = new OkHttpClient();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                String string = response.body().string();
                Log.e("OkhttpActivity", "onResponse: " + string);
            }
        });

这是Okhttp最基本的使用方式,从上述代码就可以看出OkHttp是使用是先需要创建一个Request对象然后通过client执行这个请求,我这里是使用异步的方式Okhttp自动切换到子线程进行网络请求,因为在Android中主线程是不能进行网路请求的

Request

翻译过来就是请求的意思,Request主题为以下是个部分

  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  • url这个是网路请求的地址自然是不能少的
  • method使用的请求方式,上述我们使用的是Builder模式创建的Request对象,则使用的是默认的请求方式GET
    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

这个是Request.Builder的构造函数这里默认给method赋值了GET,所以如果我们使用Builder模式创建Request对象就默认使用的GET方式发送网路请求

  • headers是Request的请求头部
  • body是我们的请求体部分

Okhttp很强大那自然是支持restful api的我们看下都是哪些函数

    public Builder get() {
      return method("GET", null);
    }

    public Builder head() {
      return method("HEAD", null);
    }

    public Builder post(RequestBody body) {
      return method("POST", body);
    }

    public Builder delete(@Nullable RequestBody body) {
      return method("DELETE", body);
    }

    public Builder delete() {
      return delete(Util.EMPTY_REQUEST);
    }

    public Builder put(RequestBody body) {
      return method("PUT", body);
    }

    public Builder patch(RequestBody body) {
      return method("PATCH", body);
    }

我们只要调用对应的函数就可以使用Okhttp发送出对应action的网路请求.

OkhttpClient

当我们调用enqueue()函数时会自动给我使用线程池执行这个网路请求,实际执行enqueue()函数的是RealCall这个类接下来我们看下它的源码

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

在最后一行okhttpClient使用调度器创建了一个异步的call
client.dispatcher().enqueue(new AsyncCall(responseCallback));

接下来我们看下这个调度器

Dispatcher

我们前面调用的enqueue()其实最终是调用到了这个类这里

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

  private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
		//判断正在执行的请求有多少个,maxReuests = 64
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        //判断和当前同一个host的请求有多少个 maxRequestsPerHost = 5
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.

        i.remove();
        executableCalls.add(asyncCall);
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }
	
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }
    return isRunning;
  }
    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }

在这里拿到了所有可以执行的call,我们再看下executorService()里面做了什么事情

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

在这里拿到了取得了一个线程池,asyncCall.executeOn(executorService());我们在之前那个函数的名称(大概翻译过来的意思就是 将这个call在这个线程池中执行)

    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        eventListener.callFailed(RealCall.this, ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

这里就是把可执行的请求放到了线程池中执行,我们直接看到RealCall#run方法

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

realCall继承自NamedRunnable 而NamedRunnable最终执行到了execute中

    @Override protected void execute() {
      boolean signalledCallback = false;
      timeout.enter();
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        e = timeoutExit(e);
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

Response response = getResponseWithInterceptorChain();这里开始调用拦截器了,从这里开始才是okhttp的重头戏


  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

okhttp内置了5个拦截器

  1. RetryAndFollowUpInterceptor 重试拦截器
  2. BridgeInterceptor 桥接拦截器
  3. CacheInterceptor 缓存拦截器
  4. ConnectInterceptor 链接拦截器
  5. CallServerInterceptor 读写拦截器

我们继续往下看okhttp是如何通过他们获取到了网络请求返回

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);

	 @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    return response;
  }

通过上面的方法开始调用到了我们第一个拦截器

RetryAndFollowUpInterceptor#intercept

注意

库引入

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

如果是Android P系统因为默认是禁用http明文请求的方式我们需要在xml中配置开启明文请求
首先在res文件夹下创建名为xml的文件夹,再在xml文件夹下创建network_security_config.xml文件内容如下

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

之后在AndroidManifest.xml的application标签下加入如下配置即可

android:networkSecurityConfig="@xml/network_security_config"

还有别忘记打开网路权限,INTERNET只要声明不需要动态申请

<uses-permission android:name="android.permission.INTERNET" />
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值