栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android进阶:OkHttp

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android进阶:OkHttp

OkHttp
  • 介绍
  • 使用
    • 分发器

介绍

        OkHttp是目前Android 使用最广泛的网络框架,包括Android4.4以后,HttpURLConnection的底层也是采用OkHttp的。甚至目前部分Java也使用OkHttp。

特点:
1. 支持HTTP2,对同一台服务器的所有请求可以共享同一个套接字(socket)。
2. 如果是非HTTP2,则可以通过连接池,降低请求延迟(内置有连接池,支持复用)。
3. 支持GZip压缩响应体。并默认适用GZip。
4. 通过缓存技术避免重复的网络请求。

        简单讲讲里面的一些逻辑。我们常听说OSI七层模型。HTTP是处于 应用层 上,他是网络服务与最终用户的一个接口,他负责数据的收发,DNS解析等。用于会话的。有了会话之后,就需要进行传输。这时候就会用到 传输层TCP。 期间会经历表示层(对数据的表示进行修改,比如压缩)和会话层(建立,管理,终止会话)。每次通讯,都需要一个TCP连接。OkHttp就以连接池技术来实现对建立的TCP进行管理,这样就比重新建立TCP连接要快很多。TCP传输则需要通过 网络层IP 进行寻址(其实socket就是对这边的TCP/IP抽象的实现,所以只要把socket缓存起来,就能共享)。然后程序中就能通过socket的OutputStream将报文发出去。
        OkHttp默认会询问服务器是否支持GZip压缩,如果支持,则服务器会使用GZip去压缩数据。
        如果我们开启了缓存机制,则OkHttp会按HTTP协议规则去缓存我们的相应数据。HTTP支持强缓存和协商缓存。当OkHttp再次请求的时候,回先去缓存区看看是否存在缓存。再决定是否需要请求服务器。

使用
// 导包,这里导入的是3.21.1
implementation 'com.squareup.okhttp3:okhttp:3.12.1'

// 构建OkHttpClient,两种方法都行。初始化的东西都是一样的。
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
// OkHttpClient okHttpClient = new OkHttpClient();

// 构造请求Request对象
Request request = new Request.Builder()
    .url(url)
    .get()	//默认就是GET请求,可以省略
    .build();
    
// 通过OkHttpClient和Request构建Call对象
Call call = okHttpClient.newCall(request);

// 1.利用Call调用enqueue(Callback)方法来执行**异步请求**,顾名思义:enqueue是将请求丢入Deque双端队列里。 源码进行了请求判定,一个call只能使用一次(比较简单,可以自己看看)。
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // TODO 请求失败
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // TODO 获得服务器返回数据
     }
});

// 2.也可以利用Call调用execute方法,execute是同步请求
 Response response = call.execute();


        代码初看:
        1.OkHttpClient初始化

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
// 在Builder()里面初始化了OkHttpClient所需要的一些默认属性和方法。
 public Builder() {
      dispatcher = new Dispatcher(); // 默认分发器
      protocols = DEFAULT_PROTOCOLS;	// 实现协议
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      eventListenerFactory = EventListener.factory(EventListener.NONE);	// 事件监听器工厂,用于创建事件监听器
      proxySelector = ProxySelector.getDefault();	// 代理选择器
      if (proxySelector == null) {
        proxySelector = new NullProxySelector();	//  代理选择器
      }
      cookieJar = CookieJar.NO_COOKIES;		// cookie策略化和持久化方案
      socketFactory = SocketFactory.getDefault();	// socket工厂
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;	// 代理服务器认证
      authenticator = Authenticator.NONE;		// 服务器认证方式
      connectionPool = new ConnectionPool();	// 连接池
      dns = Dns.SYSTEM;		// 系统DNS解析器
      followSslRedirects = true;		// 是否从HTTP重定向到HTTPS
      followRedirects = true;			// 是否重定向
      retryOnConnectionFailure = true;	 //连接失败时是否重连
      callTimeout = 0;			 //请求超时
      connectTimeout = 10_000; 		// 连接超时
      readTimeout = 10_000;			// 读超时
      writeTimeout = 10_000;		// 写超时
      pingInterval = 0;				//服务器每次发ping指令的时间间隔
    }

        2.Request初始化

 Request request = new Request.Builder()
                .url("")
                .get()	//默认就是GET请求,可以省略
                .build();

        3.Call初始化

 Call call = okHttpClient.newCall(request);
 
 @Override 
 public Call newCall(Request request) {
 	// Call 是接口,所以返回的是Call的实现类的实例化对象
    return RealCall.newRealCall(this, request, false );
 }

 static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // 初始化Call, 
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.eventListener = client.eventListenerFactory().create(call);
    return call;
  }

        4.接下来是分发器的内容了

分发器

        OkHttp分发器:Dispatcher(package okhttp3)。当然我们在构建OkHttpClient 的时候,也可以传入自定义的分发器。

  // 传入自定义分发器
  OkHttpClient okHttpClient = new OkHttpClient.Builder().dispatcher(dispatcher).build();
// 调用异步的方法
call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // TODO 请求失败
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                // TODO 获得服务器返回数据
            }
        });


// 异步方法主要实现,传入回调函数
 @Override 
 public void enqueue(Callback responseCallback) {
 	// 对该对象进行同步,这边相当于给call加上executed是否执行过的标记,如果调用过一次,则该call不能再调用,需要重新创建或者clone(),才能再调用。
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    // eventListener可以监听OkHttp各个步骤的开始或者完成时间节点,可以用来记录各个节点的执行时间。
    eventListener.callStart(this);
    // okhttpclient获取到分发器(dispatcher),然后调取该分发器的enqueue()方法,传入异步请求任务AsyncCall
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }


   void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);
    }
    // 提升权限并执行,这里面是,给准备队列中的call提升至运行队列
    promoteAndExecute();
  }

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

    List executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
    // 遍历准备队列中的call
      for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();
		// 判断运行中的call 是否大于maxRequests 可以设置
        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        // 判断同一域名下的请求是否大于maxRequestsPerHost 可以设置
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
		// 从readyAsyncCalls移出
        i.remove();
        executableCalls.add(asyncCall);
        // 添加到runningAsyncCalls队列
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }

    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      //AsyncCall 能调用线程池的
      AsyncCall asyncCall = executableCalls.get(i);
      // executorService 线程池。最后会从runningAsyncCalls队列取出交给线程池执行
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

  // 通过线程池获取线程的方法
  public synchronized ExecutorService executorService() {
    if (executorService == null) {
     // 
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

  // 线程执行asyncCall
  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!
        }
      }
    }


final class AsyncCall extends NamedRunnable {
	...
	  @Override 
	  protected void execute() {
      boolean signalledCallback = false;
      timeout.enter();
      try {
      	// 执行拦截器,获取Response 
        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 {
      	// 每当任务执行完,尝试回调promoteAndExecute()去将下一个准备队列中的call加入到running队列中
        client.dispatcher().finished(this);
      }
    }
}


  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call);
  }
  
 private  void finished(Deque calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
	// 去尝试将下一个准备队列中的call加入到running队列中
    boolean isRunning = promoteAndExecute();

    if (!isRunning && idleCallback != null) {
      idleCallback.run();
    }
  }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1014890.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号