Volley简析

282 阅读2分钟

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方法返回,或者在等待时被中断会做中断处理。