浅析OkHttp

本文将从源码角度浅析OkHttp,主要在于OkHttp处理的流程,所以叫浅析。具体的用法不是本文的重点。通过对OkHttp的基本用法来一步步探索OkHttp的运行流程。
OkHttp实际上是利用线程池来处理子线程的任务即网络请求,处理得到的结果是运行在子线程中,所以我们需要对数据通过Handler等方法处理到主线程。OkHttp利用的线程池是类似于CacheThreadPool的,具体的创建方法为:
 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;

  }
既然用到了线程池,所以这也是OkHttp也具有线程池的优点:重用线程池中的线程,我们可以同时创建许多个线程来请求网络,且不会带来额外的性能开销。
从OkHttp的基本用法,我们一步步分析流程,OkHttp的基本Get用法:
//创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();  //第一步
//创建一个Request
final Request request = new Request.Builder()
                .url("https://github.com/hongyangAndroid")
                .build();                         //第二步
//new call
Call call = mOkHttpClient.newCall(request);       //第三步
//请求加入调度
call.enqueue(new Callback()                       //第四步
        {
            @Override
            public void onFailure(Request request, IOException e)
            {
            }

            @Override
            public void onResponse(final Response response) throws IOException
            {
                    //String htmlStr =  response.body().string();
            }
        }); 

首先第一二步是定义两个对象OkHttpClient和Request。
OkHttpClient为保存网络配置的‘javabean‘,可以配置连接时间,读取时间等,最主要的是配置插值器Interceptor(OkHttp巧妙的运用了插值器功能,代码值得借鉴,关于Interceptor类,稍后重点分析)
Request类为保存请求数据的’javabean‘,可以配置url,header,请求方法等。
通过第三步的newCall方法我们创建了一个RealCall类,该类实际上是一个Runnable
/**

   * Prepares the {@code request} to be executed at some point in the future.

   */

  @Override public Call newCall(Request request) {

    return new RealCall(this, request, false /* for web socket */);

  }

第四步调用RealCall类的异步请求方法enqueue请求数据。下面我们跟着该方法,一步一步分析流程
首先来看RealCall的enqueue方法:
@Override public void enqueue(Callback responseCallback) {

    synchronized (this) {

      if (executed) throw new IllegalStateException("Already Executed");

      executed = true;

    }

    captureCallStackTrace();

    client.dispatcher().enqueue(new AsyncCall(responseCallback));    //主要看这一步

  }

调用OkHttpClient类中的dispatcher()方法返回一个Dispatcher对象,然后调用其enqueue()方法
synchronized void enqueue(AsyncCall call) {
//如果正在运行的call小于设置的最大值,那么将该Runnable加入到运行列表并执行,否则加入到等待列表
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {

      runningAsyncCalls.add(call);

      executorService().execute(call);   

    } else {

      readyAsyncCalls.add(call);

    }

  }

创建的线程池enecutorService()理论上可以容纳无穷多个Runnable,我们通过maxRequests来控制线程池中的数量。
通过executorService的execute()方法,我们会执行AsyncCall中的run方法,而AsyncCall是继承NamedRunnable的,NamedRunnable类:
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();

}

AsyncCall类会执行execute方法:

@Override protected void execute() {

      boolean signalledCallback = false;

      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) {

        if (signalledCallback) {

          // Do not signal the callback twice!

          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);

        } else {

          responseCallback.onFailure(RealCall.this, e);

        }

      } finally {

        client.dispatcher().finished(this);

      }

    }

通过 getResponseWithInterceptorChain()方法获取到从服务器返回的数据,这里面主要是对Interceptor类进行添加,来看一下方法体:
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);

    return chain.proceed(originalRequest);

  }

将Interceptor添加到ArrayList表中进行顺序执行,通过OkHttpClient的addInterceptor()方法逐步添加自定义的Interceptor,最后通过CallServerInterceptor方法获取到最终的网络数据。最后看一眼RealInterceptorChain类:
/**

 * A concrete interceptor chain that carries the entire interceptor chain: all application

 * interceptors, the OkHttp core, all network interceptors, and finally the network caller.

 */

public final class RealInterceptorChain implements Interceptor.Chain {

  private final List<Interceptor> interceptors;

  private final StreamAllocation streamAllocation;

  private final HttpCodec httpCodec;

  private final Connection connection;

  private final int index;

  private final Request request;

  private int calls;



  public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,

      HttpCodec httpCodec, Connection connection, int index, Request request) {

    this.interceptors = interceptors;

    this.connection = connection;

    this.streamAllocation = streamAllocation;

    this.httpCodec = httpCodec;

    this.index = index;

    this.request = request;

  }



  @Override public Connection connection() {

    return connection;

  }



  public StreamAllocation streamAllocation() {

    return streamAllocation;

  }



  public HttpCodec httpStream() {

    return httpCodec;

  }



  @Override public Request request() {

    return request;

  }



  @Override public Response proceed(Request request) throws IOException {

    return proceed(request, streamAllocation, httpCodec, connection);

  }



  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,

      Connection connection) throws IOException {

    if (index >= interceptors.size()) throw new AssertionError();



    calls++;



    // If we already have a stream, confirm that the incoming request will use it.

    if (this.httpCodec != null && !sameConnection(request.url())) {

      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)

          + " must retain the same host and port");

    }



    // If we already have a stream, confirm that this is the only call to chain.proceed().

    if (this.httpCodec != null && calls > 1) {

      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)

          + " must call proceed() exactly once");

    }



    // Call the next interceptor in the chain.

    RealInterceptorChain next = new RealInterceptorChain(

        interceptors, streamAllocation, httpCodec, connection, index + 1, request);

    Interceptor interceptor = interceptors.get(index);

    Response response = interceptor.intercept(next);



    // Confirm that the next interceptor made its required call to chain.proceed().

    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {

      throw new IllegalStateException("network interceptor " + interceptor

          + " must call proceed() exactly once");

    }



    // Confirm that the intercepted response isn't null.

    if (response == null) {

      throw new NullPointerException("interceptor " + interceptor + " returned null");

    }



    return response;

  }



  private boolean sameConnection(HttpUrl url) {

    return url.host().equals(connection.route().address().url().host())

        && url.port() == connection.route().address().url().port();

  }

}

其中的proceed()方法,通过遍历Interceptor列表,依次执行各自的intercept()方法,在Interceptor的实现类中,一定要调用proceed方法依次遍历剩余Interceptor。这种方法非常巧妙的获取到列表中的最后一个值,并且第一个Interceptor可以获取到最后一个Interceptor中的值,并且可以依次加载中间的类。刚开始看这段代码比较迷惑,非常棒,在针对插值器方法的时候,非常有效简洁明了,其中一个Interceptor:
public final class ConnectInterceptor implements Interceptor {

  public final OkHttpClient client;



  public ConnectInterceptor(OkHttpClient client) {

    this.client = client;

  }



  @Override public Response intercept(Chain chain) throws IOException {

    RealInterceptorChain realChain = (RealInterceptorChain) chain;

    Request request = realChain.request();

    StreamAllocation streamAllocation = realChain.streamAllocation();



    // We need the network to satisfy this request. Possibly for validating a conditional GET.

    boolean doExtensiveHealthChecks = !request.method().equals("GET");

    HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks);

    RealConnection connection = streamAllocation.connection();



    return realChain.proceed(request, streamAllocation, httpCodec, connection);

  }

}

这样整个OkHttp异步请求网络的流程就走完了,项目中异步请求用的较多。
总结:OkHttp利用线程池实现异步操作,通过Interceptor插值器来获取数据,处理数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值