2013年Google推出Volley网络请求框架,首先请求会加

public void run() { /* 隐藏部分代码 */ // Deliver a normal response or error, depending. if (mResponse.isSuccess { mRequest.deliverResponse(mResponse.result);//回调到我们一开始创建的Listenner回调中 } else { mRequest.deliverError(mResponse.error); } // If this is an intermediate response, add a marker, otherwise we're done // and the request can be finished. if (mResponse.intermediate) {//响应需要刷新的时候为true mRequest.addMarker("intermediate-response"); } else { mRequest.finish; } // If we have been provided a post-delivery runnable, run it. if (mRunnable != null) { mRunnable.run(); }

美高梅游戏网站登录,1.Volley结构图

从上图可以看到Volley分为三个线程,分别是主线程、缓存调度线程、和网络调度线程,首先请求会加入缓存队列,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程;如果在缓存中没有找到结果,则将这条请求加入到网络队列中,然后发送HTTP请求,解析响应并写入缓存,并回调给主线程。

看到四个while循环有些晕吧,让我们挑重点的说,首先从缓存队列取出请求,判断是否请求是否被取消了,如果没有则判断该请求是否有缓存的响应,如果有并且没有过期则对缓存响应进行解析并回调给主线程。接下来看看网络调度线程。

当网络请求完成后,调用了request中的parseNetworkResponse方法,用我们一开始的StringRequest来分析下。

4.NetworkDispatcher网络调度线程

NetworkDispatcher的run()方法:

 public void run() {
        Process.setThreadPriority(10);

        while(true) {
            long startTimeMs;
            Request request;
            while(true) {
                startTimeMs = SystemClock.elapsedRealtime();

                try {
                //从队列中取出请求
                    request = (Request)this.mQueue.take();
                    break;
                } catch (InterruptedException var6) {
                    if(this.mQuit) {
                        return;
                    }
                }
            }

            try {
                request.addMarker("network-queue-take");
                if(request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                } else {
                    this.addTrafficStatsTag(request);
                    //请求网络
                    NetworkResponse e = this.mNetwork.performRequest(request);
                    request.addMarker("network-http-complete");
                    if(e.notModified && request.hasHadResponseDelivered()) {
                        request.finish("not-modified");
                    } else {
                        Response volleyError1 = request.parseNetworkResponse(e);
                        request.addMarker("network-parse-complete");
                        if(request.shouldCache() && volleyError1.cacheEntry != null) {                         
                            //将响应结果存入缓存
                            this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry);
                            request.addMarker("network-cache-written");
                        }

                        request.markDelivered();
                        this.mDelivery.postResponse(request, volleyError1);
                    }
                }
            } catch (VolleyError var7) {
                var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.parseAndDeliverNetworkError(request, var7);
            } catch (Exception var8) {
                VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
                VolleyError volleyError = new VolleyError(var8);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.mDelivery.postError(request, volleyError);
            }
        }
    }

网络调度线程也是从队列中取出请求并且判断是否被取消了,如果没取消就去请求网络得到响应并回调给主线程。请求网络时调用this.mNetwork.performRequest(request),这个mNetwork是一个接口,实现它的类是BasicNetwork,我们来看看BasicNetwork的performRequest()方法:

  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();

        while(true) {
            HttpResponse httpResponse = null;
            Object responseContents = null;
            Map responseHeaders = Collections.emptyMap();

            try {
                HashMap e = new HashMap();
                this.addCacheHeaders(e, request.getCacheEntry());
                httpResponse = this.mHttpStack.performRequest(request, e);
                StatusLine statusCode1 = httpResponse.getStatusLine();
                int networkResponse1 = statusCode1.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if(networkResponse1 == 304) {
                    Entry requestLifetime2 = request.getCacheEntry();
                    if(requestLifetime2 == null) {
                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                    }

                    requestLifetime2.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(304, requestLifetime2.data, requestLifetime2.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }


...省略

从上面可以看到在12行调用的是HttpStack的performRequest()方法请求网络,接下来根据不同的响应状态码来返回不同的NetworkResponse。另外HttpStack也是一个接口,实现它的两个类我们在前面已经提到了就是HurlStack和HttpClientStack。让我们再回到NetworkDispatcher,请求网络后,会将响应结果存在缓存中,如果响应结果成功则调用this.mDelivery.postResponse(request, volleyError1)来回调给主线程。来看看Delivery的postResponse()方法:

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

来看看ResponseDeliveryRunnable里面做了什么:

 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) {
            this.mRequest = request;
            this.mResponse = response;
            this.mRunnable = runnable;
        }

        public void run() {
            if(this.mRequest.isCanceled()) {
                this.mRequest.finish("canceled-at-delivery");
            } else {
                if(this.mResponse.isSuccess()) {
                    this.mRequest.deliverResponse(this.mResponse.result);
                } else {
                    this.mRequest.deliverError(this.mResponse.error);
                }

                if(this.mResponse.intermediate) {
                    this.mRequest.addMarker("intermediate-response");
                } else {
                    this.mRequest.finish("done");
                }

                if(this.mRunnable != null) {
                    this.mRunnable.run();
                }

            }
        }
    }

第17行调用了this.mRequest.deliverResponse(this.mResponse.result),这个就是实现Request<String>抽象类必须要实现的方法,我们来看看StringRequest的源码:

public class StringRequest extends Request<String> {
    private final Listener<String> mListener;

    public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.mListener = listener;
    }

    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(0, url, listener, errorListener);
    }

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

 ...省略
}

在deliverResponse方法中调用了this.mListener.onResponse(response),最终将response回调给了Response.Listener的onResponse()方法。我们用StringRequest请求网络的写法是这样的:

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
        StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.i("wangshu", response);
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("wangshu", error.getMessage(), error);
            }
        });
        //将请求添加在请求队列中
        mQueue.add(mStringRequest);

看到第5行整个Volley的大致流程都通了吧,好了关于Volley的源码就讲到这里。

从上图可以看到Volley分为三个线程,分别是主线程、缓存调度线程、和网络调度线程,首先请求会加入缓存队列,如果发现可以找到相应的缓存结果就直接读取缓存并解析,然后回调给主线程;如果在缓存中没有找到结果,则将这条请求加入到网络队列中,然后发送HTTP请求,解析响应并写入缓存,并回调给主线程。

而request的finish方法会调用RequestQueue的finish方法

2.从RequestQueue入手

我们都知道使用Volley之前首先要创建RequestQueue:

 RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());

这也是volley运作的入口,看看newRequestQueue:

 public static RequestQueue newRequestQueue(Context context) {
        return newRequestQueue(context, (HttpStack)null);
    }

public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
        return newRequestQueue(context, stack, -1);
    }

连续调用了两个重载函数,最终调用的是:

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
        File cacheDir = new File(context.getCacheDir(), "volley");
        String userAgent = "volley/0";

        try {
            String network = context.getPackageName();
            PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
            userAgent = network + "/" + queue.versionCode;
        } catch (NameNotFoundException var7) {
            ;
        }

        if(stack == null) {
            if(VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

        BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
        RequestQueue queue1;
        if(maxDiskCacheBytes <= -1) {
            queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
        } else {
            queue1 = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network1);
        }

        queue1.start();
        return queue1;
    }

可以看到如果android版本大于等于2.3则调用基于HttpURLConnection的HurlStack,否则就调用基于HttpClient的HttpClientStack。并创建了RequestQueue,调用了start()方法:

  public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

        for(int i = 0; i < this.mDispatchers.length; ++i) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
            this.mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

    }

CacheDispatcher是缓存调度线程,并调用了start()方法,在循环中调用了NetworkDispatcher的start()方法,NetworkDispatcher是网络调度线程,默认情况下mDispatchers.length为4,默认开启了4个网络调度线程,也就是说有5个线程在后台运行并等待请求的到来。接下来我们创建各种的Request,并调用RequestQueue的add()方法:

 public <T> Request<T> add(Request<T> request) {
        request.setRequestQueue(this);
        Set var2 = this.mCurrentRequests;
        synchronized(this.mCurrentRequests) {
            this.mCurrentRequests.add(request);
        }

        request.setSequence(this.getSequenceNumber());
        request.addMarker("add-to-queue");
        //如果不能缓存,则将请求添加到网络请求队列中
        if(!request.shouldCache()) {
            this.mNetworkQueue.add(request);
            return request;
        } else {
            Map var8 = this.mWaitingRequests;
            synchronized(this.mWaitingRequests) {
                String cacheKey = request.getCacheKey();

       //之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求
                if(this.mWaitingRequests.containsKey(cacheKey)) {
                    Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
                    if(stagedRequests == null) {
                        stagedRequests = new LinkedList();
                    }

                    ((Queue)stagedRequests).add(request);
                    this.mWaitingRequests.put(cacheKey, stagedRequests);
                    if(VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
                    }
                } else {
   //没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据
                    this.mWaitingRequests.put(cacheKey, (Object)null);
                    this.mCacheQueue.add(request);
                }

                return request;
            }
        }
    }

通过判断request.shouldCache(),来判断是否可以缓存,默认是可以缓存的,如果不能缓存,则将请求添加到网络请求队列中,如果能缓存就判断之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求;没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据。
从上面可以看出RequestQueue的add()方法并没有做什么请求网络或者对缓存进行操作。当将请求添加到网络请求队列或者缓存队列时,这时在后台的网络调度线程和缓存调度线程轮询各自的请求队列发现有请求任务则开始执行,我们先看看缓存调度线程。

public class StringRequest extends Request<String> {
      private final Listener<String> mListener;

      public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
          super(method, url, errorListener);
          this.mListener = listener;
      }

      public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
          this(0, url, listener, errorListener);
      }

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

      ...省略
  }

当waitingRequests中的request添加到缓存队列后,又进入到CacheDispatcher的调度线程中了

3.CacheDispatcher缓存调度线程

CacheDispatcher的run()方法:

    public void run() {
        if(DEBUG) {
            VolleyLog.v("start new dispatcher", new Object[0]);
        }
        //线程优先级设置为最高级别
        Process.setThreadPriority(10);
        this.mCache.initialize();

        while(true) {
            while(true) {
                while(true) {
                    while(true) {
                        try {
                        //获取缓存队列中的一个请求
                            final Request e = (Request)this.mCacheQueue.take();
                            e.addMarker("cache-queue-take");
                            //如果请求取消了则将请求停止掉
                            if(e.isCanceled()) {
                                e.finish("cache-discard-canceled");
                            } else {
                            //查看是否有缓存的响应
                                Entry entry = this.mCache.get(e.getCacheKey());
                                //如果缓存响应为空,则将请求加入网络请求队列
                                if(entry == null) {
                                    e.addMarker("cache-miss");
                                    this.mNetworkQueue.put(e);
                                //判断缓存响应是否过期    
                                } else if(!entry.isExpired()) {
                                    e.addMarker("cache-hit");
                                    //对数据进行解析并回调给主线程
                                    Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                    e.addMarker("cache-hit-parsed");
                                    if(!entry.refreshNeeded()) {
                                        this.mDelivery.postResponse(e, response);
                                    } else {
                                        e.addMarker("cache-hit-refresh-needed");
                                        e.setCacheEntry(entry);
                                        response.intermediate = true;
                                        this.mDelivery.postResponse(e, response, new Runnable() {
                                            public void run() {
                                                try {
                                                    CacheDispatcher.this.mNetworkQueue.put(e);
                                                } catch (InterruptedException var2) {
                                                    ;
                                                }

                                            }
                                        });
                                    }
                                } else {
                                    e.addMarker("cache-hit-expired");
                                    e.setCacheEntry(entry);
                                    this.mNetworkQueue.put(e);
                                }
                            }
                        } catch (InterruptedException var4) {
                            if(this.mQuit) {
                                return;
                            }
                        }
                    }
                }
            }
        }
    }

    static {
        DEBUG = VolleyLog.DEBUG;
    }

看到四个while循环有些晕吧,让我们挑重点的说,首先从缓存队列取出请求,判断是否请求是否被取消了,如果没有则判断该请求是否有缓存的响应,如果有并且没有过期则对缓存响应进行解析并回调给主线程。接下来看看网络调度线程。

4.NetworkDispatcher网络调度线程
NetworkDispatcher的run()方法:

美高梅游戏网站登录 1Volley演讲时配图

这也是volley运作的入口,看看newRequestQueue:

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

public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. mResponsePoster = new Executor() { @Override public void execute(Runnable command) { handler.post; } };}

2.从RequestQueue入手
我们都知道使用Volley之前首先要创建RequestQueue:

/** * 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. * @param stack An {@link HttpStack} to use for the network, or null for default. * @return A started {@link RequestQueue} instance. */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) { } 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)); } } Network network = new BasicNetwork; RequestQueue queue = new RequestQueue(new DiskBasedCache, network);//进入DiskBasedCache构造方法可知,此处设置缓存目录,以及设定了一个默认5M的缓存大小; queue.start(); return queue;}

通过判断request.shouldCache(),来判断是否可以缓存,默认是可以缓存的,如果不能缓存,则将请求添加到网络请求队列中,如果能缓存就判断之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求;没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据。
从上面可以看出RequestQueue的add()方法并没有做什么请求网络或者对缓存进行操作。当将请求添加到网络请求队列或者缓存队列时,这时在后台的网络调度线程和缓存调度线程轮询各自的请求队列发现有请求任务则开始执行,我们先看看缓存调度线程。

存入缓存的mCache的实现是DiskBasedCache,是不是有点熟悉,没错,就是我们一开始Volley.newRequestQueue中创建RequestQueue中的一个参数,我们看下DiskBasedCache的put方法

第17行调用了this.mRequest.deliverResponse(this.mResponse.result),这个就是实现Request抽象类必须要实现的方法,我们来看看StringRequest的源码:

mNetwork.performRequest这句代码实现了请求代码,mNetwork的唯一实现为BasicNetwork,其performRequest方法主要根据HttpStack来执行网络请求并构造NetworkResponse返回;然后就是调用mDelivery.postResponse(request, response)方法回调,跟CacheDispatcher一样的流程了;

1.Volley结构图

传入需要插入数据的大小参数neededSpace和当前缓存文件总大小的记录mTotalSize计算出是否超出了设定的缓存大小,若超出则获取CacheHeader列表;CacheHeader里包含缓存文件大小等信息,遍历CacheHeader列表删除缓存,直到小于设定缓存的0.9倍,为什么是这个数?猜测是个缓存过大的标记,同时可以留有一定可缓存空间;

连续调用了两个重载函数,最终调用的是:

response字段含义:

在deliverResponse方法中调用了this.mListener.onResponse(response),最终将response回调给了Response.Listener的onResponse()方法。我们用StringRequest请求网络的写法是这样的:

public Request add(Request request) { // Tag the request as belonging to this queue and add it to the set of current requests. request.setRequestQueue;//把request与当前RequestQueue建立联系 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 {//是否应该缓存,默认所有request都缓存 mNetworkQueue.add; 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) {//当前add的request是否已经有相同的请求,若请求没有完成,则会一直存在mWaitingRequest中 // There is already a request in flight. Queue up. Queue<Request> stagedRequests = mWaitingRequests.get; if (stagedRequests == null) { stagedRequests = new LinkedList<Request>(); } stagedRequests.add;//创建一个队列并添加request mWaitingRequests.put(cacheKey, stagedRequests);//缓存含request的队列 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);//如果request没有则存入map中 mCacheQueue.add; } return request; }}

转载刘望舒的博客Android网络编程(四)从源码解析Volley

start方法主要创建了CacheDispatcher和NetworkDispatcher,并调用了对应的start方法;CacheDispatcher负责处理调度走缓存逻辑的请求,而NetworkDispatcher则是处理调度走网络的请求;一看start方法可以推测这两个类为Thread的子类,进入看果然是继承了Thread

 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) {
            this.mRequest = request;
            this.mResponse = response;
            this.mRunnable = runnable;
        }

        public void run() {
            if(this.mRequest.isCanceled()) {
                this.mRequest.finish("canceled-at-delivery");
            } else {
                if(this.mResponse.isSuccess()) {
                    this.mRequest.deliverResponse(this.mResponse.result);
                } else {
                    this.mRequest.deliverError(this.mResponse.error);
                }

                if(this.mResponse.intermediate) {
                    this.mRequest.addMarker("intermediate-response");
                } else {
                    this.mRequest.finish("done");
                }

                if(this.mRunnable != null) {
                    this.mRunnable.run();
                }

            }
        }
    }
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);
public void run() {
        if(DEBUG) {
            VolleyLog.v("start new dispatcher", new Object[0]);
        }
        //线程优先级设置为最高级别
        Process.setThreadPriority(10);
        this.mCache.initialize();

        while(true) {
            while(true) {
                while(true) {
                    while(true) {
                        try {
                            //获取缓存队列中的一个请求
                            final Request e = (Request)this.mCacheQueue.take();
                            e.addMarker("cache-queue-take");
                            //如果请求取消了则将请求停止掉
                            if(e.isCanceled()) {
                                e.finish("cache-discard-canceled");
                            } else {
                                //查看是否有缓存的响应
                                Entry entry = this.mCache.get(e.getCacheKey());
                                //如果缓存响应为空,则将请求加入网络请求队列
                                if(entry == null) {
                                    e.addMarker("cache-miss");
                                    this.mNetworkQueue.put(e);
                                    //判断缓存响应是否过期    
                                } else if(!entry.isExpired()) {
                                    e.addMarker("cache-hit");
                                    //对数据进行解析并回调给主线程
                                    Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                    e.addMarker("cache-hit-parsed");
                                    if(!entry.refreshNeeded()) {
                                        this.mDelivery.postResponse(e, response);
                                    } else {
                                        e.addMarker("cache-hit-refresh-needed");
                                        e.setCacheEntry(entry);
                                        response.intermediate = true;
                                        this.mDelivery.postResponse(e, response, new Runnable() {
                                            public void run() {
                                                try {
                                                    CacheDispatcher.this.mNetworkQueue.put(e);
                                                } catch (InterruptedException var2) {
                                                    ;
                                                }

                                            }
                                        });
                                    }
                                } else {
                                    e.addMarker("cache-hit-expired");
                                    e.setCacheEntry(entry);
                                    this.mNetworkQueue.put(e);
                                }
                            }
                        } catch (InterruptedException var4) {
                            if(this.mQuit) {
                                return;
                            }
                        }
                    }
                }
            }
        }
    }

    static {
        DEBUG = VolleyLog.DEBUG;
    }
protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders);}

可以看到如果Android版本大于等于2.3则调用基于HttpURLConnection的HurlStack,否则就调用基于HttpClient的HttpClientStack。并创建了RequestQueue,调用了start()方法:

HttpStack有实现两个类:HttpClientStack和HurlStack,都实现了performRequest方法,主要的作用是执行网络请求操作并获取返回结果;HttpClientStack使用了HttpClient进行网络通信,而HttpStack是使用HttpURLConnection;当系统版本小于9时使用HttpClientStack,反之使用HurlStack;这个判断主要是因为系统版本小于9时HttpURLConnection有bug,调用 close() 函数会影响连接池,导致连接复用失效;稳定性不如HttpClient稳定;而9之后系统作了修改,默认开启了 gzip 压缩,提高了 HTTPS 的性能,HttpURLConnection成了最佳选择;郭霖文章给出的原因

 public <T> Request<T> add(Request<T> request) {
    request.setRequestQueue(this);
    Set var2 = this.mCurrentRequests; 
    synchronized(this.mCurrentRequests) { 
    this.mCurrentRequests.add(request);
    }
   request.setSequence(this.getSequenceNumber());
   request.addMarker("add-to-queue"); //如果不能缓存,则将请求添加到网络请求队列中
   if(!request.shouldCache()) { 
      this.mNetworkQueue.add(request);
      return request;
    } else {
            Map var8 = this.mWaitingRequests; 
            synchronized(this.mWaitingRequests) {
            String cacheKey = request.getCacheKey();
 //之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests队列,不再重复请求 
           if(this.mWaitingRequests.containsKey(cacheKey)) {
            Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey); 
           if(stagedRequests == null) {
             stagedRequests = new LinkedList();
           }
           ((Queue)stagedRequests).add(request);
           this.mWaitingRequests.put(cacheKey, stagedRequests); 
          if(VolleyLog.DEBUG) {
          VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
             }
          } else { //没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据 
           this.mWaitingRequests.put(cacheKey, (Object)null); this.mCacheQueue.add(request);
          }
         return request;
       }
    }
 }

可以看到开启线程后会一直阻塞直到获取缓存队列中插入的数据,阻塞队列使用了BlockingQueue,可另外了解;获取后查找缓存中是否有response,若response过期或需要刷新则会向mNetworkQueue中插入,走网络请求,反之则使用缓存中的response;若缓存可用便调用request的parseNetworkResponse解析数据,然后就是调用mDelivery.postResponse回调;mDelivery默认的实现是创建RequestQueue时候创建的

 public static RequestQueue newRequestQueue(Context context) { 
 return newRequestQueue(context, (HttpStack)null); 
}
public static RequestQueue newRequestQueue(Context context, HttpStack stack){ 
   return newRequestQueue(context, stack, -1);
 }

Cache-Control:告诉所有的缓存机制是否可以缓存及哪种类型

  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();

        while(true) {
            HttpResponse httpResponse = null;
            Object responseContents = null;
            Map responseHeaders = Collections.emptyMap();

            try {
                HashMap e = new HashMap();
                this.addCacheHeaders(e, request.getCacheEntry());
                httpResponse = this.mHttpStack.performRequest(request, e);
                StatusLine statusCode1 = httpResponse.getStatusLine();
                int networkResponse1 = statusCode1.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if(networkResponse1 == 304) {
                    Entry requestLifetime2 = request.getCacheEntry();
                    if(requestLifetime2 == null) {
                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                    }

                    requestLifetime2.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(304, requestLifetime2.data, requestLifetime2.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }


                ...省略

默认添加Request都会添加到mCacheQueue,缓存调度会不断轮询此队列;上面说到创建了RequestQueue后会默认开启5个线程,其中包括了缓存线程CacheDispatcher,现在看下CacheDispatcher的run方法

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { 
File cacheDir = new File(context.getCacheDir(), "volley"); 
String userAgent = "volley/0";
 try { 
String network = context.getPackageName(); 
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0); 
userAgent = network + "/" + queue.versionCode;
 } 
catch (NameNotFoundException var7) { 
; 
} 
if(stack == null) { 
if(VERSION.SDK_INT >= 9) { 
stack = new HurlStack(); } 
else { 
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
 }
 }
 BasicNetwork network1 = new BasicNetwork((HttpStack)stack); 
RequestQueue queue1; 
if(maxDiskCacheBytes <= -1) { 
queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1); 
} else { 
queue1 = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network1); 
} 
queue1.start(); return queue1;
 }

到此,这句代码的流程完全走了一遍;总结一下:调用newRequestQueue创建了RequestQueue,同时开启了CacheDispatcher和NetworkDispatcher 5个线程不断阻塞轮询,当调用add方法时,会先在缓存队列mCacheQueue中插入request,此时缓存线程CacheDispatcher先查找缓存中是否有该request的响应缓存,若有且没有过期,且不需要刷新操作,则request自身的parseNetworkResponse方法解析成response且回调给主线程自己创建request的Response.Listener中的onResponse,若过期,没有缓存或需要刷新,则添加到mNetworkQueue中,NetworkDispatcher轮询获取request后,根据系统版本使用HttpClient或HttpURLConnection执行网络请求,得到响应后解析并回调给主线程,若request需要缓存且响应不为null,则存入响应缓存中;

来看看ResponseDeliveryRunnable里面做了什么:

ETag:请求变量的实体标签的当前值

从上面可以看到在12行调用的是HttpStack的performRequest()方法请求网络,接下来根据不同的响应状态码来返回不同的NetworkResponse。另外HttpStack也是一个接口,实现它的两个类我们在前面已经提到了就是HurlStack和HttpClientStack。让我们再回到NetworkDispatcher,请求网络后,会将响应结果存在缓存中,如果响应结果成功则调用this.mDelivery.postResponse(request, volleyError1)来回调给主线程。来看看Delivery的postResponse()方法:

public Request add(Request request) { /* ... ...隐藏部分代码 ...*/ // If the request is uncacheable, skip the cache queue and go straight to the network. //判断request是否需要缓存,若不需要缓存则加入mNetworkQueue中,默认Request都需要缓存, //setShouldCache可改变设置 if (!request.shouldCache { mNetworkQueue.add; return request; } /* ... ...隐藏部分代码 ...*/ mWaitingRequests.put(cacheKey, null); mCacheQueue.add;//默认的request都加入到mCacheQueue return request; }}
public void start() {
 this.stop();
 this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery); 
 this.mCacheDispatcher.start();
 for(int i = 0; i < this.mDispatchers.length; ++i) {
 NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery); this.mDispatchers[i] = networkDispatcher;
 networkDispatcher.start();
 }
 }
public synchronized void put(String key, Entry entry) { pruneIfNeeded(entry.data.length);//put之前先修正大小,避免超出限定的缓存大小 File file = getFileForKey; try { FileOutputStream fos = new FileOutputStream; CacheHeader e = new CacheHeader(key, entry); e.writeHeader; fos.write(entry.data); fos.close(); putEntry; return; } catch (IOException e) { } boolean deleted = file.delete();//try出错时会把file给delete if  { VolleyLog.d("Could not clean up file %s", file.getAbsolutePath; }}
   RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
    StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    Log.i("wangshu", response);
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e("wangshu", error.getMessage(), error);
        }
    });
    //将请求添加在请求队列中
    mQueue.add(mStringRequest);

Volley的缓存策略

美高梅游戏网站登录 2

Expires:响应过期的日期和时间

CacheDispatcher是缓存调度线程,并调用了start()方法,在循环中调用了NetworkDispatcher的start()方法,NetworkDispatcher是网络调度线程,默认情况下mDispatchers.length为4,默认开启了4个网络调度线程,也就是说有5个线程在后台运行并等待请求的到来。接下来我们创建各种的Request,并调用RequestQueue的add()方法:

void finish(Request request) { // Remove from the set of requests currently being processed. synchronized (mCurrentRequests) { mCurrentRequests.remove; } if (request.shouldCache { synchronized (mWaitingRequests) { String cacheKey = request.getCacheKey(); Queue<Request> waitingRequests = mWaitingRequests.remove;//移除该request的cacheKey,并得到缓存时创建的request队列 if (waitingRequests != null) { if (VolleyLog.DEBUG) { VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", waitingRequests.size(), cacheKey); } // Process all queued up requests. They won't be considered as in flight, but // that's not a problem as the cache has been primed by 'request'. mCacheQueue.addAll(waitingRequests);//若缓存起来的队列不为空,把里面的request全部添加到缓存队列; } } }}

3.CacheDispatcher缓存调度线程
CacheDispatcher的run()的方法:

本文由美高梅游戏网站登录发布于美高梅棋牌游戏,转载请注明出处:2013年Google推出Volley网络请求框架,首先请求会加

您可能还会对下面的文章感兴趣: