当前位置: 代码迷 >> Android >> Android Volley分析(1)
  详细解决方案

Android Volley分析(1)

热度:97   发布时间:2016-04-28 03:16:58.0
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 [email protected] 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中有两个抽象方法需要子类去实现,

/**     * 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     * [email protected] #parseNetworkResponse(NetworkResponse)}     */    abstract protected void deliverResponse(T response);

一个是 parseNetworkResponse,就是说对于返回的数据,需要怎么去解析,解析成什么类型的数据。一个具体的请求,应该知道自己想要什么结果,比如StringRequest就是将结果解析成String,而ImageRequest则是将结果解析成Bitmap,这里作为抽象方法留给具体的子类实现;

另一个是 deliverResponse,用于解析完成后将结果传递出去。这里传入的是解析好的数据类型,一般会在里面通过listener将结果传递到应用的场景下。如StringRequest,

    @Override    protected void deliverResponse(String response) {        mListener.onResponse(response);    }

3、NetworkResponse

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

    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,            boolean notModified) {        this.statusCode = statusCode;        this.data = data;        this.headers = headers;        this.notModified = notModified;    }


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线程。


  相关解决方案