Volley源码分析

来源:互联网 发布:exceed2008是什么软件 编辑:程序博客网 时间:2024/06/05 06:36

Volley源码分析

流程图

流程图有错,网络请求线程应该默认为四个
注:流程图有错,网络请求线程应该默认为四个

请求初始化

我们使用volley框架,一般会先创建请求队列 mRequestQueue = Volley.newRequestQueue(context);
会走这个构造:

    /**         * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.         *         * @param context A {@link Context} to use for creating the cache dir.         * @return A started {@link RequestQueue} instance.         */        public static RequestQueue newRequestQueue(Context context) {            return newRequestQueue(context, null);        }

这个一个参数的构造最终会走public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)这个构造,stack值为null,maxDiskCacheBytes值为-1,代表使用默认的HttpStack和默认磁盘缓存大小,该构造代码如下:

    //磁盘缓存目录,在data/data/包名/cache/volley目录    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);    String userAgent = "volley/0";    try {        String packageName = context.getPackageName();        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);        userAgent = packageName + "/" + info.versionCode;    } catch (NameNotFoundException e) {    }    //因为默认stack为null,所以会根据sdk版本创建不同的HttpStack,其中HurlStack是用HttpURLConnection进行网络请求的    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));        }    }    //创建一个BasicNetwork对象,Network是一个接口,有一个方法public NetworkResponse performRequest(Request<?> request);    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();    return queue;

其中queue = new RequestQueue(new DiskBasedCache(cacheDir), network)创建请求队列中new DiskBasedCache(cacheDir)会走如下构造,创建默认大小为5MB的磁盘缓存

    public DiskBasedCache(File rootDirectory) {    this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);    }

而new RequestQueue(new DiskBasedCache(cacheDir), network)构造最终会走这个构造:

    public RequestQueue(Cache cache, Network network, int threadPoolSize,            ResponseDelivery delivery) {        mCache = cache;        mNetwork = network;        mDispatchers = new NetworkDispatcher[threadPoolSize];        mDelivery = delivery;    }

由以上代码可以看出,系统会创建一个网络分发线程数组mDispatchers,线程数默认为4,并创建一个响应分发器mDelivery

    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;    private final ResponseDelivery mDelivery;    private NetworkDispatcher[] mDispatchers;

至此,请求队列初始化完毕

请求队列启动

请求队列启动是调用queue.start()方法,具体实现如下

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

由上可以看出,会创建一个缓存器CacheDispatcher,其实它也是个线程,并其启动它;然后遍历网络分发线程数组mDispatchers,创建网络请求线程,赋值并启动网络分发线程数组,其长度为4,也就是有4个网络请求线程,创建缓存线程和网络请求线程构造都有四个参数,mCacheQueue, mNetworkQueue, mCache, mDelivery;其中 mCache, mDelivery前面讲过一个是缓存对象,一个是响应分发器,其余两个是缓存请求队列和网络请求队列,之后我们创建的网络请求就会按情况添加到队列中.

线程启动会走run()方法,我们先看缓存线程run方法

    public void run() {    if (DEBUG) VolleyLog.v("start new dispatcher");    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);    // Make a blocking call to initialize the cache.    mCache.initialize();    Request<?> request;    while (true) {        // release previous request object to avoid leaking request object when mQueue is drained.        request = null;        try {            // Take a request from the queue.            request = mCacheQueue.take();        } catch (InterruptedException e) {            // We may have been interrupted because it was time to quit.            if (mQuit) {                return;            }            continue;        }        ...}

从这里可以看出mCacheQueue.take(),缓存队列会监视队列中的请求,如果有就会取出,然后处理,网络请求队列也是如此,在这之前我们先看这个mCache.initialize(),缓存的初始化:

    public synchronized void initialize() {    if (!mRootDirectory.exists()) {        if (!mRootDirectory.mkdirs()) {            VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());        }        return;    }    File[] files = mRootDirectory.listFiles();    if (files == null) {        return;    }    for (File file : files) {        BufferedInputStream fis = null;        try {            fis = new BufferedInputStream(new FileInputStream(file));            CacheHeader entry = CacheHeader.readHeader(fis);            entry.size = file.length();            //将缓存的头信息存入集合中            putEntry(entry.key, entry);        } catch (IOException e) {            if (file != null) {               file.delete();            }        } finally {            try {                if (fis != null) {                    fis.close();                }            } catch (IOException ignored) { }        }    }}

其中putEntry(entry.key, entry)会先把缓存的头信息取出来存入Map<> mEntries中,而不会读取缓存,到请求发生时才会读取缓存,这样既节约了时间,又避免内存溢出.

网络请求处理

  • 缓存线程的请求处理

    我们会调用RequestQueue的add(Request request)方法将请求添加进队列,由于缓存线程已启动,就会取出这个请求,进行处理:

        try {            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.                final Request<?> finalRequest = request;                mDelivery.postResponse(request, response, new Runnable() {                    @Override                    public void run() {                        try {                            mNetworkQueue.put(finalRequest);                        } catch (InterruptedException e) {                            // Not much we can do about this.                        }                    }                });            }        } catch (Exception e) {            VolleyLog.e(e, "Unhandled exception %s", e.toString());        }

    由上面可以看出,当缓存找到了并且不过期,就会从缓存中读取数据,通过Response<> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));将我们实现的parseNetworkResponse方法调用并返回Response对象

    最后调用mDelivery.postResponse(request, response),其中mDelivery就是我们初始化请求队列时创建的响应分发器

        public RequestQueue(Cache cache, Network network, int threadPoolSize) {    this(cache, network, threadPoolSize,            new ExecutorDelivery(new Handler(Looper.getMainLooper())));    }

    该分发器绑定一个主线程的handler,会在将响应post到主线程进行,通过

    @Overridepublic void postResponse(Request<?> request, Response<?> response, Runnable runnable) {    request.markDelivered();    request.addMarker("post-response");    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));}

    执行ResponseDeliveryRunnable的run()方法,

            if (mResponse.isSuccess()) {            mRequest.deliverResponse(mResponse.result);        } else {            mRequest.deliverError(mResponse.error);        }

    从这里可以看到,mRequest会调用deliverResponse和deliverError方法最终会回调我们实现的onResponse(response)和onErrorResponse(error)方法.

         @Overrideprotected void deliverResponse(T response) {    if (mListener != null) {        mListener.onResponse(response);    }}public void deliverError(VolleyError error) {    if (mErrorListener != null) {        mErrorListener.onErrorResponse(error);    }}
  • 网络线程的请求处理

    网络线程的请求处理跟缓存线程的请求处理大致相同,只不过要从网络获取数据,再缓存到本地磁盘,然后再由响应分发器分发到主线程

    try {        request.addMarker("network-queue-take");        // If the request was cancelled already, do not perform the        // network request.        if (request.isCanceled()) {            request.finish("network-discard-cancelled");            continue;        }        addTrafficStatsTag(request);        // Perform the network request.        //请求网络数据        NetworkResponse networkResponse = mNetwork.performRequest(request);        request.addMarker("network-http-complete");        // If the server returned 304 AND we delivered a response already,        // we're done -- don't deliver a second identical response.        if (networkResponse.notModified && request.hasHadResponseDelivered()) {            request.finish("not-modified");            continue;        }        // Parse the response here on the worker thread.        //解析数据        Response<?> response = request.parseNetworkResponse(networkResponse);        request.addMarker("network-parse-complete");        // Write to cache if applicable.        // TODO: Only update cache metadata instead of entire record for 304s.        //缓存到本地磁盘        if (request.shouldCache() && response.cacheEntry != null) {            mCache.put(request.getCacheKey(), response.cacheEntry);            request.addMarker("network-cache-written");        }        // Post the response back.        request.markDelivered();        mDelivery.postResponse(request, response);    } catch (VolleyError volleyError) {        volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);        parseAndDeliverNetworkError(request, volleyError);    } catch (Exception e) {        VolleyLog.e(e, "Unhandled exception %s", e.toString());        VolleyError volleyError = new VolleyError(e);        volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);        mDelivery.postError(request, volleyError);    }

    其中请求网络数据通过NetworkResponse networkResponse = mNetwork.performRequest(request)实现,mNetwork就是初始化时的Network network = new BasicNetwork(stack),sdk版本9以上是使用

    BasicNetwork类 public NetworkResponse performRequest(Request<?> request) throws VolleyError {    ...    httpResponse = mHttpStack.performRequest(request, headers);}HttpStack类 public NetworkResponse performRequest(Request<?> request) throws throws IOException, AuthFailureError {    ...    HttpURLConnection connection = openConnection(parsedUrl, request);}

    以上就是volley源码的全部解析.

0 0