Volley的使用:创建一个请求队列,然后将请求添加到队列中即可。
RequestQueue queue = Volley.newRequestQueue(Context);
Request request = new StringRequest(url, succListener, errListener);
queue.add(request);
复制代码
一个网络请求框架,最核心的就是请求如何被发送出去的。Volley是创建一个请求队列,将请求管理起来。同时开启多个子线程,无限循环的遍历队列,拿到队列后即发送出去。下面就简单过一下Volley的这个过程。
请求队列的创建过程和工作线程的启动过程的源码解析:
private static RequestQueue newRequestQueue(Context, Network) {
...
RequestQueue queue = new RequestQueue(DiskBasedCache, Network);
queue.start();
return queue;
}
复制代码
核心部分在RequestQueue及其启动后的业务:
PriorityBlockingQueue<Request<?>> mCacheQueue //
PriorityBlockingQueue<Request<?>> mNetworkQueue // 请求队列
Cache mCache
ResponseDelivery mDelivery
NetworkDispatcher[] mDispatchers // 继承于线程
CacheDispatcher mCacheDispatcher // 继承于线程
public RequestQueue(Cache, Network, int, ResponseDelivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[int];
mDelivery = delivery;
}
复制代码
这个构造函数也没有太多有意义的东西,有两个小要点:1、工作线程用数组NetworkDispatcher管理起来,一共有4个;2、ResponseDelivery用于将请求结果发送出去,但它占用的主线程new ExecutorDelivery(new Handler(Looper.getMainLooper()))
,切记不要在此出弄出ANR问题。
下面看start()方法,在这里,工作线程就被启动了。
public void start() {
mCacheDispatcher = new CacheDispatcher(...);
mCacheDispatcher.start();
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(...);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
复制代码
start()方法中CacheDispatcher和NetworkDispatcher都是线程,start()最重要的工作就是启动缓存线程和工作线程,并分别把队列传递给线程。既然NetWorkDispatcher是线程,那就直接看run()方法。
public void run() {
while (true) {
processRequest();
}
}
private void processRequest() throws InterruptedException {
Request<?> request = mQueue.take();
processRequest(request);
}
复制代码
NetWorkDispatcher的工作就是无限循环,从队列中取出请求发送出去。这种无限循环遍历队列,在Android及诸多框架中都是很常见的写法,基本有两个问题弄明白了,这个框架基本也就通了。1、无限循环一直占用着CPU,为什么不会导致应用卡死;2、队列遍历完,线程终止了怎么办。这里面的核心就是PriorityBlockingQueue,阻塞队列。
这里面的核心就在于它使用的队列,PriorityBlockingQueue。这是一种线程安全的阻塞队列,当所有元素都被取出后,继续取元素将导致线程释放锁,进去等待状态。直到队列中被添加新的元素才会被唤醒。
看源码,take()方法(这里是class文件的代码),看到notEmpty.await()这一句,很像Object的wait(),就应该想到是不是线程会释放CPU。这里的确会释放CPU,但它又不是Object.wait(),这个我们稍后再讲。
public E take() throws InterruptedException {
ReentrantLock var1 = this.lock;
var1.lockInterruptibly();
Object var2;
try {
while((var2 = this.dequeue()) == null) {
this.notEmpty.await();
}
} finally {
var1.unlock();
}
return var2;
}
复制代码
第2个问题,队列遍历完了的情况。看入列的方法,这个会唤起刚才的中断的遍历过程。
public boolean offer(E var1) {
notEmpty.signal();
}
复制代码
Volley中,业务线程的等待与继续是由PriorityBlockingQueue中的Condition notEmpty控制的,Condition.await()使当前线程释放锁进入等待队列,Condition.signal会使得当前线程从等待队列中移至到同步队列中去,直到获得了lock后才会从await方法返回,或者在等待时被中断会做中断处理。