Volley

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RequestQueue mQueue = Volley.newRequestQueue(this);
StringRequest request = new StringRequest(Request.Method.GET, "http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Log.d(TAG, s);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.d(TAG, volleyError.getMessage(), volleyError);
}
});
mQueue.add(request);

时序图

uml
uml

分析

  • Volley.newRequestQueue()方法

    有几个重载函数,最终是调用的这里,可以看到首先根据 sdk 版本是否大于等于9,去生成不同的 Network 对象.
    (可以看到在 sdk9 之前,不建议使用 HttpUrlConnection)
    然后初始化缓存目录,实例化 RequestQueue 对象,最后调用 start() 方法并 return queue.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
    BasicNetwork network;
    if (stack == null) {
    if (Build.VERSION.SDK_INT >= 9) {
    network = new BasicNetwork(new HurlStack());
    } else {
    // Prior to Gingerbread, HttpUrlConnection was unreliable.
    // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
    // At some point in the future we'll move our minSdkVersion past Froyo and can
    // delete this fallback (along with all Apache HTTP code).
    String userAgent = "volley/0";
    try {
    String packageName = context.getPackageName();
    PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
    userAgent = packageName + "/" + info.versionCode;
    } catch (NameNotFoundException e) {
    }

    network = new BasicNetwork(
    new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
    }
    } else {
    network = new BasicNetwork(stack);
    }
    return newRequestQueue(context, network);
    }
    private static RequestQueue newRequestQueue(Context context, Network network) {
    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    queue.start();
    return queue;
    }
  • Network/BasicNetwork/HurlStack/HttpClientStack 分别是啥?

    BasicNetwork 是 Network 的实现类,只有一个 performRequest 祖传方法,具体是根据 request 执行网络请求返回 NetworkResponse.

    1
    2
    3
    4
    5
    6
    public interface Network {
    /**
    * Performs the specified request.
    */
    NetworkResponse performRequest(Request<?> request) throws VolleyError;
    }

    HurlStack 和 HttpClientStack 是 HttpStack 的两个子类,分别是 HttpUrlConnection 的实现和 HttpClient的实现,
    也就是真正执行网络请求的地方,可以看出 Network 内部执行网络请求是调用了它.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public interface HttpStack {
    /**
    * Performs an HTTP request with the given parameters.
    * @return the HTTP response
    */
    HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
    throws IOException, AuthFailureError;

    }
  • DiskBasedCache 是什么

    看名字可以猜出是缓存相关的,它是 Cache 的具体实现类,主要是管理缓存的,包括读取缓存,写入缓存,清除缓存等.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public interface Cache {
    Entry get(String key);
    void put(String key, Entry entry);
    void initialize();
    void invalidate(String key, boolean fullExpire);
    void remove(String key);
    void clear();
    class Entry {
    //...
    }
    }
  • RequestQueue 作用是什么

    分析到这里,就可以知道它是很重要的类了,它的构造函数需要传入 Cache 缓存管理对象, Network
    网络请求类, threadPoolSize 线程池大小, 和 ResponseDelivery 对象,
    ResponseDelivery 是第一次出现,它的作用就是将请求结果,response/error 返回给调用者.

    1
    2
    3
    4
    5
    6
    7
    public RequestQueue(Cache cache, Network network, int threadPoolSize,
    ResponseDelivery delivery) {
    mCache = cache;
    mNetwork = network;
    mDispatchers = new NetworkDispatcher[threadPoolSize];
    mDelivery = delivery;
    }
    1
    2
    3
    4
    5
    public interface ResponseDelivery {
    void postResponse(Request<?> request, Response<?> response);
    void postResponse(Request<?> request, Response<?> response, Runnable runnable);
    void postError(Request<?> request, VolleyError error);
    }
  • RequestQueue.start() 方法做了什么

    start() 首先会调用 stop(), 然后实例化 CacheDispatcher 对象和 mDispatchers 数组,
    并分别启动线程,默认 mDispatchers 长度是4,也就是启动一个缓存线程,4个工作线程.
    注意 mCacheQueue 和 mNetworkQueue 都是优先阻塞队列,且4个工作线程公用 mNetworkQueue

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    private final NetworkDispatcher[] mDispatchers;
    private CacheDispatcher mCacheDispatcher;
    private final PriorityBlockingQueue<Request<?>> mCacheQueue =
    new PriorityBlockingQueue<>();
    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
    new PriorityBlockingQueue<>();

    public void start() {
    stop(); // Make sure any currently running dispatchers are stopped.
    // Create the cache dispatcher and start it.
    mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
    mCacheDispatcher.start();
    // Create network dispatchers (and corresponding threads) up to the pool size.
    for (int i = 0; i < mDispatchers.length; i++) {
    NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
    mCache, mDelivery);
    mDispatchers[i] = networkDispatcher;
    networkDispatcher.start();
    }
    }
    public void stop() {
    if (mCacheDispatcher != null) {
    mCacheDispatcher.quit();
    }
    for (final NetworkDispatcher mDispatcher : mDispatchers) {
    if (mDispatcher != null) {
    mDispatcher.quit();
    }
    }
    }
  • RequestQueue.add() 方法做了些什么

    首先将 request 添加到 mCurrentRequests 集合,通过 setSequence()方法设置一个序列号,
    最后根据 shouldCache() 方法判断 request 是否需要缓存,如果需要将它添加到 mCacheQueue 中,否则添加到 mNetworkQueue 中.
    然后就完了,返回 request 对象.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();

    public <T> Request<T> add(Request<T> request) {
    // Tag the request as belonging to this queue and add it to the set of current requests.
    request.setRequestQueue(this);
    synchronized (mCurrentRequests) {
    mCurrentRequests.add(request);
    }
    // Process requests in the order they are added.
    request.setSequence(getSequenceNumber());
    request.addMarker("add-to-queue");

    // If the request is uncacheable, skip the cache queue and go straight to the network.
    if (!request.shouldCache()) {
    mNetworkQueue.add(request);
    return request;
    }
    mCacheQueue.add(request);
    return request;
    }
  • 添加 request 后,NetworkDispatcher 和 CacheDispatcher 是怎么处理的?
    在上一步中,request 根据缓存添加到 mCacheQueue 或 mNetworkQueue 阻塞队列中,这两个阻塞队列是被关联在 CacheDispatcher 和 NetworkDispatcher 中了。
    可以想到这两分发器肯定是阻塞取出请求做处理。

    • CacheDispatcher

      主要看它的 run() 方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
        public void run() {
      // 省略部分代码
      while (true) {
      final Request<?> request = mCacheQueue.take();
      // 省略部分代码
      if (request.isCanceled()) {
      request.finish("cache-discard-canceled");
      continue;
      }
      Cache.Entry entry = mCache.get(request.getCacheKey());
      if (entry == null) {
      request.addMarker("cache-miss");
      // Cache miss; send off to the network dispatcher.
      if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
      mNetworkQueue.put(request);
      }
      continue;
      }
      .....
      mDelivery.postResponse(request, response);
      }
      }

      和我猜想的一样,死循环,从阻塞队列中取出 request ,然后再做处理,判断是否去掉,判断是否过期,判断缓存中是否存在,如果不存在则加入到 mNetworkQueue ,
      代表需要联网获取,否则,直接回调 mDelivery.postResponse 也就是结束的回调。

      总结一下,CacheDispatcher 主要是判断缓存是否可用,如果可用直接返回,不用网络请求了,否则,
      会将 request 丢给 mNetworkQueue, 最终是由 NetworkDispatcher 处理的.

    • NetworkDispatcher

      它的 run 方法和上述 CacheDispatcher 类似,只不过是请求网络,再判断是否需要缓存,如果需要则保存,最后回调 mDelivery.

  • ExecutorDelivery 是怎么处理响应的
    ExecutorDelivery 的默认实现是 NetworkDispatcher,在 RequestQueue 构造方法里可以看到,
    传入了主线程的 Handler 对象,在 postResponse 和 postError 方法中,实际上调用了 handler.post()方法,
    在主线程执行,而 ResponseDeliveryRunnable 的 run 方法里,
    通过判断 mResponse.isSuccess() 请求是否成功,回调 request 的 deliverResponse()
    和 deliverError()方法,最终回调了我们自定义的回调方法.

    总结一下,它的作用就是:将响应的结果 response 回调给 request 中的回调方法,并在主线程中进行.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    private final Executor mResponsePoster;
    mResponsePoster = new Executor() {
    @Override
    public void execute(Runnable command) {
    handler.post(command);
    }
    };
    @Override
    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
    request.markDelivered();
    request.addMarker("post-response");
    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    }

    @Override
    public void postError(Request<?> request, VolleyError error) {
    request.addMarker("post-error");
    Response<?> response = Response.error(error);
    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
    }
    private class ResponseDeliveryRunnable implements Runnable {
    private final Request mRequest;
    private final Response mResponse;
    private final Runnable mRunnable;

    public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
    mRequest = request;
    mResponse = response;
    mRunnable = runnable;
    }
    @Override
    public void run() {
    if (mRequest.isCanceled()) {
    mRequest.finish("canceled-at-delivery");
    return;
    }
    if (mResponse.isSuccess()) {
    mRequest.deliverResponse(mResponse.result);
    } else {
    mRequest.deliverError(mResponse.error);
    }
    // ignore some code
    }
    }
  • 并发时怎么处理的?
    由于采用了阻塞队列,所有的联网请求最终都是添加到 mNetworkQueue 这个队列中的,默认工作分发器 NetworkDispatcher 有4个,它们会从这个队列中取出请求,然后处理。
    打个比方,当有一堆工作来的时候,4个人同时处理,且保证独立,也就是一个工作不会2个人同时做。

  • HTTP 响应内容的解析在哪里?
    在 request 的 parseNetworkResponse 里,比如 StringRequest 就是最简单的。这个方法在 NetworkDispatcher 处理请求完后调用,并最终传递给 ResponseDelivery ,再到回调.