Volley之RequestQueue

Volley的使用参考郭大神的博客鸿洋大神的博客,最近几天一直在学习Volley框架,这个是google推荐的。已经封装的相当不错了,至少对于一些轻量级的网络请求是很有优势的,比如接口请求。我们只要直接去使用就好了。
首先我们知道的就是Volley的核心
RequestQueue
Request
我们先来看看创建RequestQueue对象:
要创建一个RequestQueue对象,
RequestQueue mQueue = Volley.newRequestQueue(context);
那么为什么不是通过new的方法呢?我们也可以顺便跟着去看看源码,
我们首先进入的是一个Volley类,我们可以看到我们真正调用的是这个方法:

/**
  创建一个线程池,并且通过RequestQueue#start()来启动
 *
 * @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.getFilesDir(), "volley");
        String userAgent = "volley/0";

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

        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 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
        queue1.start();
        return queue1;
    }
 /**
 * 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);
}

通过这个方法我们可以看到Volley的作用就是简单的创建RequestQueue对象,它需要传一个context用来创建缓存文件。还有传一个HttpStack 实例参数,这个实例只是一个方法performRequest,通过网络请求后返回HttpResponse对象。我们在newRequestQueue的时候,直接传这个参数为null,那么它就会通过判断API版本,来决定是使用HurlStack还是HttpClientStack。至于这两个概念,我们只需知道HurlStack内部使用HttpURLConnection执行网络请求,HttpClientStack内部使用HttpClient执行网络请求,详细参考博客。然后通过stack,创建一个BasicNetwork ,它是实现Network的一个实例,也是和网络请求打交道的实例。Network的performRequest和HttpStack的performRequest区别NetWork返回的NetworkResponse是通过封装HttpStack.performRequest得到的。我们先来看下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();
                //1、缓存请求的时候,添加Cache接口Entry类封装头部信息
                this.addCacheHeaders(e, request.getCacheEntry());
                //2、调用 HttpStack 对象去网络中获取数据,返回httpResonse 对象。
                httpResponse = this.mHttpStack.performRequest(request, e);
                //3、根据状态编码来返回不同的Response对象,如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。 
                StatusLine statusCode2 = httpResponse.getStatusLine();
                int networkResponse1 = statusCode2.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if(networkResponse1 != 304) {
                    byte[] responseContents1;
                    if(httpResponse.getEntity() != null) {
                        responseContents1 = this.entityToBytes(httpResponse.getEntity());
                    } else {
                        responseContents1 = new byte[0];
                    }

                    long requestLifetime1 = SystemClock.elapsedRealtime() - requestStart;
                    this.logSlowRequests(requestLifetime1, request, responseContents1, statusCode2);
                    if(networkResponse1 >= 200 && networkResponse1 <= 299) {
                        return new NetworkResponse(networkResponse1, responseContents1, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                    }

                    throw new IOException();
                }

                Entry requestLifetime = request.getCacheEntry();
                if(requestLifetime == null) {
                    return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }

                requestLifetime.responseHeaders.putAll(responseHeaders);
                return new NetworkResponse(304, requestLifetime.data, requestLifetime.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
            } catch (SocketTimeoutException var12) {
            //4、BasicNetwork实现了重试的机制,如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。 
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException var13) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException var14) {
                throw new RuntimeException("Bad URL " + request.getUrl(), var14);
            } catch (IOException var15) {
                boolean statusCode = false;
                NetworkResponse networkResponse = null;
                if(httpResponse == null) {
                    throw new NoConnectionError(var15);
                }

                int statusCode1 = httpResponse.getStatusLine().getStatusCode();
                VolleyLog.e("Unexpected response code %d for %s", new Object[]{Integer.valueOf(statusCode1), request.getUrl()});
                if(responseContents == null) {
                    throw new NetworkError(networkResponse);
                }

                networkResponse = new NetworkResponse(statusCode1, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                if(statusCode1 != 401 && statusCode1 != 403) {
                    throw new ServerError(networkResponse);
                }

                attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
            }
        }
    }

然后再通过传递network参数来创建RequestQueue。其中还有一个参数我们可以看到Volley中使用Cache接口的子类DiskBasedCache做缓存,这是一个文件缓存,磁盘默认为5M。Cache接口有一个initialize方法用来初始化缓存,这个方法可能会执行耗时操作,需要在后台线程中执行。这个方法会把每一个网络请求根据cacheKey一一对应的头部信息缓存在内存中的文件,然后通过cacheKey来获取这些一一对应的头部信息。我们就来看看头部保存了一些什么?

//缓存文件的大小
 public long size;
 //用于一一对应网络请求的唯一标识
 public String key;
 //http请求缓存相关的标识
 public String etag;
 //服务器返回数据的时间
 public long serverDate;
 //最后一次缓存时间
 public long lastModified;
  //缓存过期时间,默认softTtl和ttl相同
 public long ttl;
 // 缓存新鲜度时间
 public long softTtl;
// 服务器还回来的头部信息
 public Map<String, String> responseHeaders;

然后我们再来看看缓存内容,再Cache接口中

//服务器返回数据
 public byte[] data;
 //下面同上
 public String etag;
 public long serverDate;
 public long lastModified;
 public long ttl;
 public long softTtl;
 public Map<String, String> responseHeaders = Collections.emptyMap();

看完了要保存的东西,我们在来看看缓存的方法

    public synchronized void put(String key, Entry entry) {
     //判断是否有足够的缓存空间来缓存新的数据
        this.pruneIfNeeded(entry.data.length);
        //创建一个缓存文件
        File file = this.getFileForKey(key);

        try {
            FileOutputStream deleted1 = new FileOutputStream(file);
             //用entry里面的数据,再封装成一个CacheHeader
            DiskBasedCache.CacheHeader e = new DiskBasedCache.CacheHeader(key, entry);
              //写入头部缓存信息
            boolean success = e.writeHeader(deleted1);
            if(!success) {
            //缓存不成功头部处理
                deleted1.close();
                VolleyLog.d("Failed to write header for %s", new Object[]{file.getAbsolutePath()});
                throw new IOException();
            } else {
            //缓存头部成功后再写缓存内容
                deleted1.write(entry.data);
                deleted1.close();
                this.putEntry(key, e);
            }
        } catch (IOException var7) {
            boolean deleted = file.delete();
            if(!deleted) {
                VolleyLog.d("Could not clean up file %s", new Object[]{file.getAbsolutePath()});
            }

        }
    }

详细缓存机制参考博客
再来看下RequestQueue对象,

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

    }

start方法里面,有缓存线程和网络线程这两个线程,如果网络请求没有缓存或者缓存没有记录或者缓存过期的话,那就创建一个网络线程请求NetworkDispatcher 。

  public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Request<?> request;
        while (true) {
            try {
                // 1、调用 mQueue的take()方法从队列中获取请求,如果没有请求,则一直阻塞在那里等待,直到队列中有新的请求到来。
                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");

                // 2、判断请求有没有被取消,如果被取消,则重新获取请求。
                if (request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                    continue;
                }

                addTrafficStatsTag(request);

                // 3、调用Network对象将请求发送到网络中,并返回一个 NetworkResponse对象。
                NetworkResponse networkResponse = mNetwork.performRequest(request);
                request.addMarker("network-http-complete");

                // 如果服务器返回一个未修改(304)的响应,并且这个请求已经发送过响应对象,不需要再继续,因为没改过
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish("not-modified");
                    continue;
                }

                // 4、调用请求的pareseNetworkResonse方法,将NetworkResponse对象解析成相对应的Response对象。
                Response<?> response = request.parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");

                // 5、判断请求是否需要缓存,如果需要缓存,则将其Response中cacheEntry对象放到缓存mCache中。
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // /6、调用 mDelivery将Response对象传到主线程中进行UI更新。
                request.markDelivered();
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {
                parseAndDeliverNetworkError(request, volleyError);//有错误,也会调用到mDelivery,将错误信息传回到主线程,进行提示
            } catch (Exception e) {
                VolleyLog.e(e, "Unhandled exception %s", e.toString());
                mDelivery.postError(request, new VolleyError(e));
            }
        }
    }

最后附上思维图

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值