当前位置: 首页 > 工具软件 > RequestQueue > 使用案例 >

Volley源码学习笔记_RequestQueue和BasicNetWork

融焕
2023-12-01

1.开始

Volley也只是听过没用过,新接的项目里面请求用的是Volley,只能赶鸭子上架的看了些简单的使用。现在理解下源码。(ps:这里不涉及有关图片相关的部分pps:理解不对的地方请指出,灰常感谢)

2.Volley的使用

关于Volley的使用,比较简洁的。

  //首先创建请求队列
  RequestQueue requestQueue = Volley.newRequestQueue(Context);
  //创建一个request
  Request request=new Request() {...};
  //将request添加到请求队列中
  requestQueue.add(request);

下面根据上面的三行代码,来一步步的看相关的实现源码。

3.RequestQueue

我们先看 new RequestQueue的代码,它只传入了一个Context

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

 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
        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 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;
    }

以上代码包含的内容还是很多的。主要是先根据VERSION.SDK_INT
来判断使用什么网络连接请求类。然后实例化一个BasicNetWork来进行网络交互请求。 然后创建一个请求队列,传入一个DiskBasedCache,一个BasicNetwork,最后队列start。下面先看一下RequestQueue的构造函数。

   public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {

       //下面这5个有的是直接在外面初始化的
        this.mSequenceGenerator = new AtomicInteger();
        this.mWaitingRequests = new HashMap();
        this.mCurrentRequests = new HashSet();
        this.mCacheQueue = new PriorityBlockingQueue();
        this.mNetworkQueue = new PriorityBlockingQueue();
        //这里
        this.mCache = cache;
        this.mNetwork = network;
        this.mDispatchers = new NetworkDispatcher[threadPoolSize];
        this.mDelivery = delivery;
    }

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

    public RequestQueue(Cache cache, Network network) {
        this(cache, network, 4);
    }

从下往上, this(cache, network, 4);这是的4就是线程数目,记得之前好像还是可以自己输入的现在默认是4个。这里有一个ExecutorDelivery,主要作用就是传递消息(response),可以看到它的实现要传递一个Handler。这个后期再看。下面看一下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();
        }

    }

从上面可以看出,只要new了一个RequestQueue那么就会开启1个缓存线程,4个网络请求
线程。这就意味着一次最多只能并发5个线程,如果缓存线程没有命中,那么最多并发4个网
络请求线程。NetworkDispatcher基本就是从队列中获取请求,然后请求网络数据
(BasicNetWork)同时更新到UI线程。(ExecutorDelivery)。

既然是队列了,那他是如何addRequest的呢?

 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.
        //请求不用缓存就加入到网络请求队列中,但是这个值默认是true
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);
            return request;
        }


//根据key值判断请求是否已经在重复请求队列,但是会发现最终都是要添加到这个队列里面的
        // 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<>();
                }
                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;
        }
    }

RequestQueue的add方法,从这里我们可以看到四个参数 mWaitingRequests ,mCurrentRequests ,mCacheQueue ,mNetworkQueue。分别是重复请求队列,当前请求或者等待请求集合,缓存队列,网络请求队列,这里重复队列就是一个Map集合,key是cacheKey,就是getUrl。mCacheQueue ,mNetworkQueue是一个优先级队列 。根据优先级来执行,同等优先级是无序的。
当mCacheQueue或者mNetworkQueue利用add方法添加请求之后,在运行的线程就会接收到请求(Cache线程接收到请求,会将相应的请求提那家到mNetworkQueue,这样在请求线程中就可以处理请求队列中的请求),从而去处理相对应的请求,最后将处理的结果由mDelivery来发送到主线程进行更新。


BasicNetWork的具体作用有:

1)对于已经有缓存的请求,添加其头部信息,如下:
    private void addCacheHeaders(Map<String, String> headers, Entry entry) {
        if(entry != null) {
            if(entry.etag != null) {
                headers.put("If-None-Match", entry.etag);
            }

            if(entry.serverDate > 0L) {
                Date refTime = new Date(entry.serverDate);
                headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
            }

        }
    }
2)调用 HttpStack 对象去网络中获取数据,返回httpResonse 对象。
 httpResponse = this.mHttpStack.performRequest(request, e);
3)根据状态编码来返回不同的NetworkResponse对象

如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。

   if(networkResponse1 == 304) {
                    return new NetworkResponse(304, request.getCacheEntry().data, responseHeaders1, true);
                }
                 ...

  long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                this.logSlowRequests(requestLifetime, request, responseContents1, statusCode2);
                if(networkResponse1 >= 200 && networkResponse1 <= 299) {
                    return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, 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);
                if(statusCode1 != 401 && statusCode1 != 403) {
                    throw new ServerError(networkResponse);
                }             
4)BasicNetwork实现了重试的机制

如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。

   private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError {
        RetryPolicy retryPolicy = request.getRetryPolicy();
        int oldTimeout = request.getTimeoutMs();

        try {
            retryPolicy.retry(exception);
        } catch (VolleyError var6) {
            request.addMarker(String.format("%s-timeout-giveup [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)}));
            throw var6;
        }

        request.addMarker(String.format("%s-retry [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)}));
    }

下面看一下3的内容

//具体代码就不贴了
   public NetworkResponse performRequest(Request<?> request) throws VolleyError {
   ....
}
public interface Network {
    NetworkResponse performRequest(Request<?> var1) throws VolleyError;
}

BasicNetwork是Network 的实现类。。Network 的方法只有一个performRequest(),参数是Request。用来获取网络请求到的数据,然后在NetworkDispatcher中被解析后通过ExecutorDelivery将请求结果传到UI线程。
这里有一段代码:

  byte[] responseContents1;
                if(httpResponse.getEntity() != null) {
                    responseContents1 = this.entityToBytes(httpResponse.getEntity());
                } else {
                    responseContents1 = new byte[0];
                }
 if(networkResponse1 >= 200 && networkResponse1 <= 299) {
                    return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false);
                }

这是请求到数据的时候,然后在状态码返回200-299之间的时候创建一个NetworkResponse对象并将其data设置为获取到内容。除了在状态码304的时候,还有一个地方也创建了NetworkResponse对象。这里的responseContents是开始创建的一个空对象。

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

以上。不对的地方麻烦大家指出,非常感谢。

参考

[1].http://blog.csdn.net/linmiansheng/article/details/22653841

[2].http://blog.csdn.net/mr_liabill/article/details/50241543
[3].http://f303153041.iteye.com/blog/2281350

 类似资料: