Volley(2)源码分析

来源:互联网 发布:淘宝付款不发货骗术 编辑:程序博客网 时间:2024/04/30 15:58

由于Volley框架逻辑很清晰,类多但是都精简,很多都是接口。

第二篇,从入口开始,挨个分析Volley各个类的功能。

1.Volley.java

这个类是Volley框架的入口,其类图如下



成员变量只有一个String值,是默认的缓存文件名。

总共有4个方法,都叫newRequestQueue,用于构建RequestQueue。

其中,后3个方法最终都是通过调用第1个来实现的,没有传的参数都设为默认值。

来看第一个newRequestQueue方法。

 String userAgent = "volley/0";        try {            String packageName = context.getPackageName();            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);            userAgent = packageName + "/" + info.versionCode;        } catch (NameNotFoundException e) {        }        if (stack == null) {            if (Build.VERSION.SDK_INT >= 9) {                stack = new HurlStack();            } else {                // Prior to Gingerbread, HttpUrlConnection was unreliable.                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));            }        }

一般我们在调用Volley的时候并不会自己创建一个HttpStack传进去,这种情况下,Volley会根据当前的SDK_VERSION值来创建一个HttpStack。实际上现在的安卓手机已经几乎不存在低于SDK版本9的了。因此这里的stack基本上是个HurlStack。

Network network = new BasicNetwork(stack);                RequestQueue queue;        if (maxDiskCacheBytes <= -1)        {                // No maximum size specified                queue = new RequestQueue(new DiskBasedCache(cacheDir), network);        }        else        {                // Disk cache size specified                queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);        }        queue.start();


第二步,用刚才的stack对象作为参数构建以个NetWork对象netWork,然后和一个DiskBasedCache对象一起作为参数构建1个RequestQueue,最后调用queue.start()。


总结下,整个流程如下:


可以通过参数maxDiskCacheBytes来指定Cache大小。默认值为5MB

private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;

2.DiskBasedCache.java

这个类并不是很重要,只要看一下google的注释就好拉。就是上面的Cache,默认大小为5MB

 Cache implementation that caches files directly onto the hard disk in the specified directory. The default disk usage size is 5MB, but is configurable.


3.BasicNetwork.java


BasicNetwork实现了Network接口。因此大家都知道这个类的重点是什么了。



BasicNetwork中有2个重要的成员:HttpStack mHtppStack 和 ByteArrayPool mPool。

这两个成员都在其构造函数中传入。

public BasicNetwork(HttpStack httpStack)public BasicNetwork(HttpStack httpStack, ByteArrayPool pool)

前者调用了后者。


performRequest方法调用了下面的4个方法。

因此,从performRequest方法入手就能弄清楚这个类干了什么了。

long requestStart = SystemClock.elapsedRealtime();        while (true) {            ……        }


首先记录了时间,然后是个死循环,所有的东西都在死循环里面。死循环里是一个try{}catch{}串,try中:

                // Gather headers.                Map<String, String> headers = new HashMap<String, String>();                addCacheHeaders(headers, request.getCacheEntry());                httpResponse = mHttpStack.performRequest(request, headers);                StatusLine statusLine = httpResponse.getStatusLine();                int statusCode = statusLine.getStatusCode();                responseHeaders = convertHeaders(httpResponse.getAllHeaders());                // Handle cache validation.                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {                    Entry entry = request.getCacheEntry();                    if (entry == null) {                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,                                responseHeaders, true,                                SystemClock.elapsedRealtime() - requestStart);                    }                    // A HTTP 304 response does not have all header fields. We                    // have to use the header fields from the cache entry plus                    // the new ones from the response.                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5                    entry.responseHeaders.putAll(responseHeaders);                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,                            entry.responseHeaders, true,                            SystemClock.elapsedRealtime() - requestStart);                }                                // Handle moved resources                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {                        String newUrl = responseHeaders.get("Location");                        request.setRedirectUrl(newUrl);                }                // Some responses such as 204s do not have content.  We must check.                if (httpResponse.getEntity() != null) {                  responseContents = entityToBytes(httpResponse.getEntity());                } else {                  // Add 0 byte response as a way of honestly representing a                  // no-content request.                  responseContents = new byte[0];                }                // if the request is slow, log it.                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;                logSlowRequests(requestLifetime, request, responseContents, statusLine);                if (statusCode < 200 || statusCode > 299) {                    throw new IOException();                }                return new NetworkResponse(statusCode, responseContents, responseHeaders, false,                        SystemClock.elapsedRealtime() - requestStart);            }



这里,BasicNetwork把request交给成员mHttpStack去处理了。也就是说,所有的网络请求,都是HttpStack做的。

HttpStack负责了处理网络请求,并且返回HttpResponse

 Map<String, String> headers = new HashMap<String, String>();   addCacheHeaders(headers, request.getCacheEntry());   httpResponse = mHttpStack.performRequest(request, headers);

找return的地方,

第1处, HTTP304:

if (statusCode == HttpStatus.SC_NOT_MODIFIED) {                    Entry entry = request.getCacheEntry();                    if (entry == null) {                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,                                responseHeaders, true,                                SystemClock.elapsedRealtime() - requestStart);                    }                    // A HTTP 304 response does not have all header fields. We                    // have to use the header fields from the cache entry plus                    // the new ones from the response.                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5                    entry.responseHeaders.putAll(responseHeaders);                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,                            entry.responseHeaders, true,                            SystemClock.elapsedRealtime() - requestStart);                }



第2处:
return new NetworkResponse(statusCode, responseContents, responseHeaders, false,                        SystemClock.elapsedRealtime() - requestStart);



其中,

responseHeaders = convertHeaders(httpResponse.getAllHeaders()); responseContents = entityToBytes(httpResponse.getEntity());


convertHeaders负责把HttpResponse的header转化成Map形式。

entityToBytes负责把HttpResponse的Entity转化成Byte数组。

总结一下,BasicNetwork将request交给HttpStack处理,并从返回的HttpResponse中解析出Map形式的Header和Byte[]形式的数据。

但是为什么要一个死循环来做这件事呢。

看到各个catch{}块中,会发现有很多attemptRetryOnException(),只要不抛出错误(满足重试策略),就会一直attemptRetryOnException。

回头再研究重试策略的东西,先看RequestQueue。

用流程图来总结一下:



4.RequestQueue.java

RequestQueue是目前为止Volley中最庞大的类了,有320行,在这里去掉一些无关紧要的,精简一下。



它有2个内部接口,

/** Callback interface for completed requests. */    public static interface RequestFinishedListener<T> {        /** Called when a request has finished processing. */        public void onRequestFinished(Request<T> request);    }    /**     * A simple predicate or filter interface for Requests, for use by     * {@link RequestQueue#cancelAll(RequestFilter)}.     */    public interface RequestFilter {        public boolean apply(Request<?> request);    }


RequestFinishedListener是Request的结束监听,RequestFilter用于Request筛选,具体作用后面说。

它有3个构造函数,

public RequestQueue(Cache cache, Network network, int threadPoolSize,                        ResponseDelivery delivery) {        mCache = cache;        mNetwork = network;        mDispatchers = new NetworkDispatcher[threadPoolSize];        mDelivery = delivery;    }    public RequestQueue(Cache cache, Network network, int threadPoolSize) {        this(cache, network, threadPoolSize,                new ExecutorDelivery(new Handler(Looper.getMainLooper())));    }    public RequestQueue(Cache cache, Network network) {        this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);    }


3个参数的意义:

@param cache A Cache to use for persisting responses to disk   //Response的缓存@param network A Network interface for performing HTTP requests  //用于处理Http请求@param threadPoolSize Number of network dispatcher threads to create  //network dispather数目


接下来是2个非常重要的成员:用于保存Cache请求和Network请求的2个队列

private final PriorityBlockingQueue<Request<?>> mCacheQueue =            new PriorityBlockingQueue<Request<?>>();    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =        new PriorityBlockingQueue<Request<?>>();


此外RequestQueue中保存了正在处理的Request集合和等待中的Request集合。

private final Map<String, Queue<Request<?>>> mWaitingRequests =            new HashMap<String, Queue<Request<?>>>();    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();


最后3个需要提到的成员,1个CacheDispatcher、一个NetworkDispatcher数组(大小由构造函数中的threadPoolSize决定,默认为4),以及1个ResponseDelivery来分发请求结果。

private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
 /** Response delivery mechanism. */    private final ResponseDelivery mDelivery;    /** The network dispatchers. */    private NetworkDispatcher[] mDispatchers;    /** The cache dispatcher. */    private CacheDispatcher mCacheDispatcher;

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


start方法中,启动了CacheDispatcher和全部的NetworkDispathcher。

 public void cancelAll(RequestFilter filter) {       synchronized (mCurrentRequests) {            for (Request<?> request : mCurrentRequests) {                if (filter.apply(request)) {                    request.cancel();                    request.onFinish();                }            }       }    }


这里的filter就是内部接口的实现了,用于cancel掉那些符合filter条件的request。

add方法的流程如下:





5.CacheDispatcher.java

CacheDispathcer的成员非常少,不算构造函数只有2个方法。



这5个成员的作用/含义如下:

mCacheQueue : 等待分类的resquest 队列

mNetworkQueue        :被分到Network请求的request 队列

 mDelivery : 用于分发response

mQuit: 线程终止的标识

其整个过程如下



6.NetworkDispatcher.java

NetworkDispatcher和CacheDispatcher相对应,用于分发走网络的request。



其run的流程如下


7.ResponseDelivery.java

结果分发接口,内有3个方法

第一个postResponse直接调用的第二个postResponse,并传参数null。

8.ExecutorDelivery.java 

实现了ResponseDelivery接口,用于分发response和error。

其有一个Runnable类型的内部类

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;        }        @SuppressWarnings("unchecked")        @Override        public void run() {            // If this request has canceled, finish it and don't deliver.            ……            // Deliver a normal response or error, depending.            if (mResponse.isSuccess()) {                mRequest.deliverResponse(mResponse.result);            } else {                mRequest.deliverError(mResponse.error);            }            ……       }    }


其run方法如下:



public void postResponse(Request<?> request, Response<?> response) {        postResponse(request, response, null);    }    @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));    }


ExecutorDelivery将分发任务交给内部类去处理,而内部类又把分发任务交给了request去处理。最终,分发任务到了各Request的实现类中处理。

此处以JsonRequest为例。

  @Override    protected void deliverResponse(T response) {        if (mListener != null) {            mListener.onResponse(response);        }    }


最终还是交给了mListener,也就是我们构造request的时候传入的onResponseListener和OnRequestListener。

总结一下,整个框架的Response流程如图





8.RetryPolicy.java

重试策略接口。只有3个方法

  public int getCurrentTimeout();  public int getCurrentRetryCount();  public void retry(VolleyError error) throws VolleyError;


9.DefaultRetryPolicy.java  

实现了RetryPolicy接口,是Volley默认的重试策略。

其重试策略为,当重试次数大于指定次数的时候,就抛出异常放弃重试。

@Override    public void retry(VolleyError error) throws VolleyError {        mCurrentRetryCount++;        mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);        if (!hasAttemptRemaining()) {            throw error;        }    }    /**     * Returns true if this policy has attempts remaining, false otherwise.     */    protected boolean hasAttemptRemaining() {        return mCurrentRetryCount <= mMaxNumRetries;    }


其中,指定次数mMaxNumRetries在构造函数中传入,大小由我们指定

 public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) {        mCurrentTimeoutMs = initialTimeoutMs;        mMaxNumRetries = maxNumRetries;        mBackoffMultiplier = backoffMultiplier;    }


10.Cache.java

缓存接口,提供了Get、remove、put、clear方法。有内部类Entry,封装了缓存数据。


总结几点使用过程中比较实用的:

1.NetworkDispatcher[ ]的size可以在RequestQueue的构造函数中传参指定,默认为4。

2.Cache的maxSize可以在newRequestQueue中以参数形式传入,默认为5MB。

3.重写Requst的getHeaders方法,放入我们自己需要的header。

4.可以自己实现RetryPolicy来定义自己的重试策略。

最后放一张Volley的总框架图,和圆圈相连的类我们可以自由地去实现,在Volley的核心代码中,这些部分都是以接口存在的,这就是Volley极强的扩展性所在。




本文在总结过程中参考了:

http://a.codekk.com/detail/Android/grumoon/Volley%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90

0 0