4、Volley解析(二),源码的深入分析一,缓存线程和网络请求线程

来源:互联网 发布:知乎抄袭quora 编辑:程序博客网 时间:2024/05/20 13:12

前言

首先来看一下谷歌的官方流程图
这里写图片描述
从图中我们可以看出Volley工作的时候有三种线程,分别是主线程、请求线程、缓存线程,图中的流程大致如下:首先将请求放入缓存队列(队列中会根据优先级来排序),缓存线程将请求从缓存线程中取出,如果缓存存在,则将缓存的数据取出解析,传到主线程。如果不存在则将请求队列去执行网络请求。请求完成之后,再把结果发送给主线程。这里就是利用线程生产者-消费者模式

1. 源码的入口

分析某个开源项目的源码,首先要找到它的入口,然后再抽丝剥茧,逐步分析。这样思路会比较清晰。

//这个方法要做的工作是创建工作线程池的默认实例,并调用 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {        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,由系统自己判断使用哪种请求方式        if (stack == null) {            if (Build.VERSION.SDK_INT >= 9) {            //adk版本在9或者以上,使用HttpURLConnection            //它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。                stack = new HurlStack();            } else {                // 在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。                       stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));            }        }        Network network = new BasicNetwork(stack);        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);        //        queue.start();        return queue;    }

今天这一篇博客,先不去研究用哪种请求方式,先介绍各个线程的工作流程。
创建好了HttpStack之后,接下来又创建了一个Network对象,它是用于根据传入的HttpStack对象来处理网络请求的,紧接着new出一个RequestQueue对象,并调用它的start()方法进行启动,然后将RequestQueue返回。
看到这里我们肯定会疑问,start()到底做了什么工作,会不会和线程有关呢?下面我们就来看一下。

    public void start() {          //确保当前运行的任何调度都已停止。         stop();          // 创建缓存的调度器并启动(缓存线程)        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);          mCacheDispatcher.start();          // 创建网络请求的调度器,默认开启四条网络请求的线程        for (int i = 0; i < mDispatchers.length; i++) {              NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,                      mCache, mDelivery);              mDispatchers[i] = networkDispatcher;              networkDispatcher.start();          }      }  

这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,也就是说当调用了satrt()之后,就会有五个线程一直在后台运行,不断等待网络请求的到来,其中CacheDispatcher是缓存线程,NetworkDispatcher是网络请求线程。

我们首先来看一下CacheDispatcher

    @Override    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();        //死循环,一直在运行执行任务        while (true) {            try {                //首先从mCacheQueue中取出一个任务,                // at least one is available.                final Request<?> request = mCacheQueue.take();                request.addMarker("cache-queue-take");                // 判断请求任务是否取消,取消了就跳出,进入下个循环。                if (request.isCanceled()) {                    request.finish("cache-discard-canceled");                    continue;                }                // 取出缓存                Cache.Entry entry = mCache.get(request.getCacheKey());                //判断是否为空                if (entry == null) {                    request.addMarker("cache-miss");                    // 如果为空,就将这个任务加入到网络请求的队列当中,这里就用到了生产者-消费者模式,此时缓存线程充当的是生产者对象。                    mNetworkQueue.put(request);                    //然后跳出循环                    continue;                }                //如果缓存过期的话同样是将任务加入网络请求队列当中。然后跳出当前循环                if (entry.isExpired()) {                    request.addMarker("cache-hit-expired");                    request.setCacheEntry(entry);                    mNetworkQueue.put(request);                    continue;                }                // 下面就是肯定存在缓存,浴室将缓存读取出来,解析。                request.addMarker("cache-hit");                Response<?> response = request.parseNetworkResponse(                        new NetworkResponse(entry.data, entry.responseHeaders));                request.addMarker("cache-hit-parsed");                //如果缓存的数据不需要刷新                if (!entry.refreshNeeded()) {                    // 将数据发送到主线程                    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.                            }                        }                    });                }            } catch (InterruptedException e) {                // We may have been interrupted because it was time to quit.                if (mQuit) {                    //循环结束,安全                     return;                }                continue;            }        }    }

到这里相信大家已经对CacheDispatcher有了足够的了解,下面我们就来看看NetworkDispatcher 主要职责是什么代码如下

 @Override    public void run() {        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        while (true) {            long startTimeMs = SystemClock.elapsedRealtime();            Request<?> request;            try {                // Take a request from the queue.                request = mQueue.take();            } catch (InterruptedException e) {                // We may have been interrupted because it was time to quit.                if (mQuit) {                    return;                }                continue;            }            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.                //支持304重定向                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);            }        }    }    private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {        error = request.parseNetworkError(error);        mDelivery.postError(request, error);    }

这样 CacheDispatcher 和 NetworkDispatcher就构成了生产者和消费者模式,当然充当生产者的不仅仅是CacheDispatcher 线程,还有主线程。其实CacheDispatcher 和 NetworkDispatcher大部分逻辑都是相同的,理解了一个另一个就不难理解了。今天这篇博客就到这里,下篇将为大家分析具体的网络请求是怎么样的。

0 0
原创粉丝点击