Volley源码分析

2018-12-04  本文已影响11人  鹈鹕醍醐

volley是2013年谷歌IO大会推出的,是google在OKHttp之前的官方推荐网络框架。适用于通讯频率高,传输数量级小的使用场景,其api 简单易用,麻雀虽小却又五脏俱全

Request request = new StringRequest(url, new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        response 在UI线程回调
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        error 在UI线程回调
    }
}).setShouldCache(false).setTag(UserActivity.this);
Volley.newRequestQueue(this).add(request);

示例代码相当简单,实例化一个RequestQueen,然后实例化一个Request并add到queue中结束。如下是具体过程解析

Request构建

基于面向对象的设计思路,每个请求封装为Request对象,需要关注的重要属性如下:

RequestQueue构建

示例代码,不要关注语法错误
public static RequestQueue newRequestQueue(Context context, @Nullable HttpStack stack, int maxDiskCacheBytes) {
  定义缓存目录
  File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
  定义请求agent
  String userAgent = appPackageName + "/" + appVersionCode;

  HttpClientStack 拼装网络请求成HttpUriRequest并交给HttpClient执行以获取response
  HttpClientStack stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));

  BasicNetwork中转层,获取到原始response后根据StatusLine信息拼装为volley的NetworkResponse
  Network network = new BasicNetwork(stack);

  RequestQueue传送带/任务分配者,默认手下有4个等待干活的员工(NetworkDispatcher),一个同步传送带BlockingQueue输出任务
  RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
  queue.start();
  return queue;
}

在方法体的最后创建了一个RequestQueue对象并调用了start()方法

public class RequestQueue {
  private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
  public RequestQueue(Cache cache, Network network, int threadPoolSize,ResponseDelivery delivery) {
    mCache = cache;        缓存对象
    mNetwork = network;    网络请求中转层
    mDispatchers = new NetworkDispatcher[threadPoolSize];  4个全天无休不要加班费的机器员工
    mDelivery = delivery;       流水线最后的成品分发
  }
  public void start() {
    stop();  // Make sure any currently running dispatchers are stopped.
    缓存调度器
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
    mCacheDispatcher.start();

    依据threadPoolSize创建指定数量的网络调度器
    for (int i = 0; i < mDispatchers.length; i++) {
      NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mCache, mDelivery);
      mDispatchers[i] = networkDispatcher;
      networkDispatcher.start();
    }
  }
}
public <T> Request<T> add(Request<T> request) {
        request.setRequestQueue(this);
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }
      ......
      不需要缓存的请求则直接添加到mNetworkQueue并返回
        if (!request.shouldCache()) {  
            mNetworkQueue.add(request);
            return request;
        }
       将请求添加到缓存队列中
       synchronized (mWaitingRequests) {
            String cacheKey = request.getCacheKey();
            Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
            stagedRequests.add(request);
            mWaitingRequests.put(cacheKey, stagedRequests);
            return request;
        }
    }

接下来梳理下volley的工作流程

public class NetworkDispatcher extends Thread {
   @Override
   public void run() {
      PriorityBlockingQueue在take()时会上锁,确保线程安全,每个Dispatcher不会取到重复Request
      Request<?> request = BlockingQueue.take();
      if (request.isCanceled()) {
        request.finish("network-discard-cancelled");
        continue;
      }
      NetworkResponse networkResponse = BasicNetwork.performRequest(request);
      Response<?> response = request.parseNetworkResponse(networkResponse)
      request.markDelivered();
      mDelivery.postResponse(request, response);
      (catch VolleyError | Exception  error){
          mDelivery.postError(request, error)
      }
   }
}
public class BasicNetwork{
  中介,24小时开业揽活,然后把活分给HttpStack
  public NetworkResponse performRequest(Request<?> request){
    while (true) {
      httpResponse = mHttpStack.performRequest(request, headers);
      StatusLine statusLine = httpResponse.getStatusLine();
      int statusCode = statusLine.getStatusCode();
      if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
          Entry entry = request.getCacheEntry();
          return new NetworkResponse(······);
      }else {······}
    }
  }
}
public class HttpClientStack implements HttpStack{
  Volley 通过newRequestQueue构造的  AndroidHttpClient
  protected final HttpClient mClient;

  @Override
  public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders){

    将volley的Request转换为HttpClient使用的HttpUriRequest

    HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
    addHeaders(httpRequest, additionalHeaders);
    addHeaders(httpRequest, request.getHeaders());
    onPrepareRequest(httpRequest);
    HttpParams httpParams = httpRequest.getParams();
    int timeoutMs = request.getTimeoutMs();
    HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
    HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
    最终活分配给了HttpClient去执行
    return mClient.execute(httpRequest);
  }
}
class ResponseDeliveryRunnable implements Runnable{
@Override
public void run() {
  判断请求是否取消,避免网络延迟时deliverResponse导致context泄漏
  if (mRequest.isCanceled()) {
    mRequest.finish("canceled-at-delivery");
    return;
  }
  分发请求的响应,已StringRequest为例,无操作直接扔给mListener.onResponse(response);
  if (mResponse.isSuccess()) {
    mRequest.deliverResponse(mResponse.result);
  } else {
    mRequest.deliverError(mResponse.error);
  }
}

Volley使用时的细节与注意事项

上一篇 下一篇

猜你喜欢

热点阅读