Volley解析

Volley:

    Volley采用了典型的门面模式,一般的框架广泛采用这种模式,只提供一个或几个门面类,这样方便第三方去学习;而所谓的门面模式就是他负责自己封闭系统和外界系统的交互,而不允许外部系统直接和内部系统进行交互,所有的交互都通过这个门面来完成。
     Volley的工作流程:
(1) 第一步创建初始化一个RequestQueue队列(注意该队列是一个线程阻塞的队列,即BlockQueue)
    在创建这个队列的时候它进行了一系列的初始化工作:
1. File  cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);默认是5M,地址为apk的cache文件里面
2.创建Client即管理网络的栈  stack  = new  HurlStack ();
3.创建网络任务 Network network = new BasicNetwork(stack);  
4.创建工作队列RequestQueue: queue  =   new   RequestQueue ( new   DiskBasedCache (cacheDir ,   maxDiskCacheBytes ) ,  network) ;
这个过程中把任务和缓存的引用交给了 RequestQueue方便RequestQueue进行下一步操作
(2)   开启队列循环   queue .start () ;
在这个过程中它又进行了如下操作:
CacheDispatcher mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);  
创建一个缓存线程:用来分发缓存任务;并开启运行它;
创建四个(默认也可以通过new不同的构造进行设置)net线程并开启
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }  
这个开启运行的过程是关键所在,我们看它做了哪些工作:
首先缓存线程:
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 设置线程优先级为后台线程
核心代码如下:
   while  ( true ) {
            final   Request<?>  request  =   mCacheQueue.take () ;
          逻辑判断是否需要刷新过期等等;然后如果不能用缓存则把加入到net线程之中,如果是不需要刷新
          且没有过期那么就把把分配给 ResponseDelivery 进行处理
    } 
在这个过程中,由于 mCacheQueue是实现了 BlockingQueue的, 因而它拿取的时候是处于一个线程
阻塞的状态的。
研究下它是怎么实现线程阻塞的:
他这里对应的实现类是 PriorityBlockingQueue,我们看一下它take方法得源码:
 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        E result;
        try {
            while ( (result = dequeue()) == null)//在这里进行了一个循环如果为空不断的取出queue里的元素如果最后为空,那
                notEmpty.await();               // 么就让等待,这里面notEmpty是一个Condition,这是JDK1.5以后推出的用来代替
        } finally {                                      // Object的wait和notify()方法,使用awit()和singal()方法,操作并发更加的高效和
            lock.unlock();                         // 安全,废话好多,其实也就是说这里当这个queue里没有元素的时候它是处于wait状态
        }                                                       // 的,当wait时线程会释放资源
        return result;
 }
在队列循环过程中它是获取缓存文件中内容转化为实体(以url为键标示的),这理应是在net线程里进行处理的;
(3)开启net线程
net线程也是利用blockqueue进行线程阻塞的;
网络请求的代码是通过以下进行的:
NetworkResponse networkResponse = mNetwork.performRequest(request);  
mNetwork是在创建队列时传进去的,   Network  network  =   new   BasicNetwork ( stack ) ;
最终调用的是httpResponse = mHttpStack.performRequest(request, headers);
这个mHttpStack其实就是   stack   =   new   HurlStack () ;(SDK9以上采用这个,SDK9以下使用 HttpClientStack
这里发现个这个:
 map.putAll(additionalHeaders);
        if (mUrlRewriter != null) {
            String rewritten = mUrlRewriter.rewriteUrl(url);
            if (rewritten == null) {
                throw new IOException("URL blocked by rewriter: " + url);
        }
      url = rewritten;
 }   
这是相当于转换URL的,我们可以通过在创建requestqueue时将之传入,并复写其rewriteUrl的方法来转换url地址
最终访问网络的实现是这样:将最终结果封装在了 BasicHttpResponse 里面,它这个封装的过程是很漂亮的
           URL  parsedUrl  =   new   URL (url) ;
        HttpURLConnection connection = openConnection(parsedUrl, request);
        for (String headerName : map.keySet()) {
            connection.addRequestProperty(headerName, map.get(headerName));
        }
        setConnectionParametersForRequest(connection, request);
        // Initialize HttpResponse with data from the HttpURLConnection.
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
        int responseCode = connection.getResponseCode();
        if (responseCode == -1) {
            // -1 is returned by getResponseCode() if the response code could not be retrieved.
            // Signal to the caller that something was wrong with the connection.
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        StatusLine responseStatus = new BasicStatusLine(protocolVersion,
                connection.getResponseCode(), connection.getResponseMessage());  
              BasicHttpResponse response = new BasicHttpResponse(responseStatus);   
           response .setEntity ( entityFromConnection (connection)) ;
             for  ( Entry<String,   List<String>>  header  :  connection .getHeaderFields () .entrySet ()) {
            if (header.getKey() != null) {
                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
                response.addHeader(h);
            }
        }  
       下面是它封装实体的部分:
       private   static   HttpEntity   entityFromConnection ( HttpURLConnection   connection ) {
        BasicHttpEntity entity = new BasicHttpEntity();
        InputStream inputStream;
        try {
            inputStream = connection.getInputStream();
        } catch (IOException ioe) {
            inputStream = connection.getErrorStream();
        }
        entity.setContent(inputStream);
        entity.setContentLength(connection.getContentLength());
        entity.setContentEncoding(connection.getContentEncoding());
        entity.setContentType(connection.getContentType());
        return entity;
    }  
    访问完成封装好Response以后;打标记,根据request是否需要缓存来决定是否缓存到缓存文件里面,
    分发:mDelivery.postResponse(request, response);
(4)分发的操作
    mDelivery 也是在构建RequestQueue时创建的; 默认情况下只是
   new ExecutorDelivery(new Handler(Looper.getMainLooper()),可以看出采用getMainLooper方法也是可以在子线程创建Handler
   来刷新UI的而不是仅仅只能在主线程创建Handler;
     分发的具体实现
    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
        request.markDelivered();
        request.addMarker("post-response");
        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    }
       public   void   run () {
            // If this request has canceled, finish it and don't deliver.
            if (mRequest.isCanceled()) {
                mRequest.finish("canceled-at-delivery");
                return;
            }
            // Deliver a normal response or error, depending.
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } 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) {
                mRequest.addMarker("intermediate-response");
            } else {
                mRequest.finish("done");
            }
            // If we have been provided a post-delivery runnable, run it.
            if (mRunnable != null) {
                mRunnable.run();
            }
     }  

看一下它是怎么实现优先级这个功能的,requestqueue每次取出request时都调用的是这个方法
     private E dequeue() {
        int n = size - 1;
        if (n < 0)
            return null;
        else {
            Object[] array = queue;
            E result = (E) array[0];
            E x = (E) array[n];
            array[n] = null;
            Comparator<? super E> cmp = comparator;//这是核心通过比较器进行了排序
            if (cmp == null)
                siftDownComparable(0, x, array, n);
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
            return result;
        }
    }  

(5)添加请求任务
       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;
        }
    }  
(6)缓存策略:
主要在 HttpHeaderParser里面进行的设置















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值