首页 > 代码库 > Android Volley分析(一)

Android Volley分析(一)

Volley是Android系统下的一个网络通信库,为Android提供简单快速的网络操作(Volley:Esay, Fast Networking for Android),下面是它的结构:

技术分享

既然是网络通信库,自然会涉及到网络的基础操作:请求和响应,也是最基本的概念。客户端发出请求,服务端返回响应的字节数据,客户端解析得到想要的结果。Volley怎么设计这些基本的概念?

一、组件

1、Network

网络操作的定义,传入请求Request,得到响应NetworkResponse

public interface Network {
    /**
     * Performs the specified request.
     * @param request Request to process
     * @return A {@link NetworkResponse} with data and caching metadata; will never be null
     * @throws VolleyError on errors
     */
    public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}

2、Request

请求的定义,网络请求的参数、地址等信息

public Request(int method, String url, Response.ErrorListener listener) {
        mMethod = method;
        mUrl = url;
        mErrorListener = listener;
        setRetryPolicy(new DefaultRetryPolicy());

        mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
    }

在Request中有两个抽象方法需要子类去实现,

一个是 parseNetworkResponse,就是说对于返回的数据,需要怎么去解析,解析成什么类型的数据。一个具体的请求,应该知道自己想要什么结果,比如StringRequest就是将结果解析成String,而ImageRequest则是将结果解析成Bitmap;

另一个是 deliverResponse,用于解析完成后将结果传递出去。这里传入的是已经解析的结果,子类负责处理返回的解析结果,一般会在里面通过listener返回到应用的场景下。

/**
     * Subclasses must implement this to parse the raw network response
     * and return an appropriate response type. This method will be
     * called from a worker thread.  The response will not be delivered
     * if you return null.
     * @param response Response from the network
     * @return The parsed response, or null in the case of an error
     */
    abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

    

    /**
     * Subclasses must implement this to perform delivery of the parsed
     * response to their listeners.  The given response is guaranteed to
     * be non-null; responses that fail to parse are not delivered.
     * @param response The parsed response returned by
     * {@link #parseNetworkResponse(NetworkResponse)}
     */
    abstract protected void deliverResponse(T response);

3、NetworkResponse

网络请求通用返回结果,存储在data中

    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
            boolean notModified) {
        this.statusCode = statusCode;
        this.data = http://www.mamicode.com/data;>


4、Response<T>

响应结果的封装,最终结果result,缓存结构cacheEntry,出错信息error

private Response(T result, Cache.Entry cacheEntry) {
        this.result = result;
        this.cacheEntry = cacheEntry;
        this.error = null;
    }

二、执行过程

有了上面的基本数据结构,之后就是考虑怎么去操作这些结构,完成从请求到响应的整个过程。这里是整个Volley最核心的部分,也是体现作者设计思想的部分,涉及到任务调度、异步处理等。

1、RequestQueue

请求队列,所有请求都会通过RequestQueue的add方法加入到内部的队列里来等待处理,当请求结束得到响应结果后会调用finish方法将请求移出请求队列。

RequestQueue中包含以下成员:

  • Cache 缓存结构,用于缓存响应结果;
  • Network 网络操作的实现
  • NetworkDispatcher 网络任务调度器
  • CacheDispatcher 缓存任务调度器
  • ResponseDelivery 响应投递,用于将结果从工作线程转移到UI线程
  • cacheQueue 缓存任务队列
  • networkQueue 网络任务队列

RequestQueue完成两项工作:

启动、停止调度器:

/**
     * Starts the dispatchers in this queue.
     */
    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();
        }
    }

    /**
     * Stops the cache and network dispatchers.
     */
    public void stop() {
        if (mCacheDispatcher != null) {
            mCacheDispatcher.quit();
        }
        for (int i = 0; i < mDispatchers.length; i++) {
            if (mDispatchers[i] != null) {
                mDispatchers[i].quit();
            }
        }
    }

将请求添加到相应的队列中,之后各个调度器会自行取出处理

    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;
        }

        // Insert request into stage if there's already a request with the same cache key in flight.
        synchronized (mWaitingRequests) {
            String cacheKey = request.getCacheKey();
            if (mWaitingRequests.containsKey(cacheKey)) {
                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);
                mWaitingRequests.put(cacheKey, stagedRequests);
                if (VolleyLog.DEBUG) {
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                }
            } else {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);
                mCacheQueue.add(request);
            }
            return request;
        }
    }

从上面可以看出,一个请求不要求缓存的话会被直接加到networkQueue中,否则会加到cacheQueue中。那调度器是怎么自行取出来并进行处理呢?

2、CacheDispatcher,NetworkDispatcher

调度器是线程,队列阻塞,有请求就执行,没有就等待。对缓存调度器CacheDispatcher,如果在缓存中没有找到响应结果,就会将请求添加到网络调度器NetworkDispatcher中

while (true) {
            try {
                // Get a request from the cache triage queue, blocking until
                // at least one is available.
                final Request<?> request = mCacheQueue.take();
                request.addMarker("cache-queue-take");

                // If the request has been canceled, don't bother dispatching it.
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }

                // Attempt to retrieve this item from cache.
                Cache.Entry entry = mCache.get(request.getCacheKey());
                if (entry == null) {
                    request.addMarker("cache-miss");
                    // Cache miss; send off to the network dispatcher.
                    mNetworkQueue.put(request);
                    continue;
                }

                // If it is completely expired, just send it to the network.
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    mNetworkQueue.put(request);
                    continue;
                }

                // We have a cache hit; parse its data for delivery back to the request.
                request.addMarker("cache-hit");
                Response<?> response = request.parseNetworkResponse(
                        new NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker("cache-hit-parsed");

                if (!entry.refreshNeeded()) {
                    // Completely unexpired cache hit. Just deliver the response.
                    mDelivery.postResponse(request, response);
                } else {
                    // Soft-expired cache hit. We can deliver the cached response,
                    // but we need to also send the request to the network for
                    // refreshing.
                    request.addMarker("cache-hit-refresh-needed");
                    request.setCacheEntry(entry);

                    // Mark the response as intermediate.
                    response.intermediate = true;

                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(request);
                            } catch (InterruptedException e) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }

NetworkDispatcher则是负责执行网络操作获取响应,调用Request解析响应从而得到指定的返回数据类型,将结果加入缓存,使用delivery将结果返回到UI线程。


Android Volley分析(一)