Volley 核心源码解析(三)

狂草 2016-03-08

Volley的任务调度模型

接着上一节的RequestQueue,在Volley初始化RequestQueue的时候会执行RequestQueue的start()方法,在start方法中初始化了,缓存调度器和网络调度器。

publicvoidstart(){

stop();//Makesureanycurrentlyrunningdispatchersarestopped.

//Createthecachedispatcherandstartit.

mCacheDispatcher=newCacheDispatcher(mCacheQueue,mNetworkQueue,mCache,mDelivery);

mCacheDispatcher.start();

//Createnetworkdispatchers(andcorrespondingthreads)uptothepoolsize.

for(inti=0;i<mDispatchers.length;i++){

NetworkDispatchernetworkDispatcher=newNetworkDispatcher(mNetworkQueue,mNetwork,

mCache,mDelivery);

mDispatchers[i]=networkDispatcher;

networkDispatcher.start();

}

}

看看NetworkDispatcher和CacheDispatcher是什么东东?

NetworkDispatcherextendsThread

CacheDispatcherextendsThread

结果两个都是线程类。

再看看循环体中往一个叫做mDispatchers[i]的数组中赋值了若干NetworkDispatcher,且每个NetworkDispatcher都在创建的时候就启动了。

找到mDispatchers的定义:

privatestaticfinalintDEFAULT_NETWORK_THREAD_POOL_SIZE=4;

mDispatchers=newNetworkDispatcher[threadPoolSize];

原来是个默认4个元素的线程组。

看到这里我似乎想到了线程池的基本概念,没错这就是个线程池。

看看具体的NetworkDispatcher是什么样的?

做过JAVA开发的都知道继承thread类一定要重写run()方法

在NetworkDispatcher中run方法如下:

方法太长一段一段的来看哈

因为是要做线程池嘛,所以线程要一直工作,所以一进run方法就是while(true){}

了,

Request<?>request=mQueue.take();

mQueue:mNetworkQueue

在PriorityBlockingQueue队列中take方法如下:

publicEtake()throwsInterruptedException{

finalReentrantLocklock=this.lock;

lock.lockInterruptibly();

Eresult;

try{

while((result=dequeue())==null)

notEmpty.await();

}finally{

lock.unlock();

}

returnresult;

}

意思就是加锁-->取出一个请求->释放锁->原队列中请求减少一个

这样就保证了使用volley发送请求的时候能按照发送请求的顺序去执行。

接下来从队列中取出请求之后,给请求设置备注,判断请求时否被取消,如果被取消就finish。

request.addMarker("network-queue-take");

//Iftherequestwascancelledalready,donotperformthe

//networkrequest.

if(request.isCanceled()){

request.finish("network-discard-cancelled");

continue;

}

紧接着,执行该请求:

//Performthenetworkrequest.

NetworkResponsenetworkResponse=mNetwork.performRequest(request);

后面就是对networkResponse的一些状态判断和解析。

Response<?>response=request.parseNetworkResponse(networkResponse);

在volley中解析NetworkResponse的具体方法交给Request的子类去实现。如,ImageRequest,JsonRequest,StringRequest等

同时,缓存这个已经执行的请求:

if(request.shouldCache()&&response.cacheEntry!=null){

mCache.put(request.getCacheKey(),response.cacheEntry);

request.addMarker("network-cache-written");

}

看到这里,我们可以得出一个结论,Volley初始化RequestQueue的时候创建了一个

默认4个大小的线程池,每个线程同步的从PriorityBlockingQueue类型的请求队列中拿出一个请求并执行。

接下来看看CacheDispatcher缓存任务调度:

/**Thequeueofrequestscominginfortriage.*/

privatefinalBlockingQueue<Request<?>>mCacheQueue;

/**Thequeueofrequestsgoingouttothenetwork.*/

privatefinalBlockingQueue<Request<?>>mNetworkQueue;

与NetworkDispatcher不同的是CacheDispatcher不仅有缓存队列还有请求队列,

同样是while(true){request=mCacheQueue.take();;...}

不停的从mCacheQueue拿出缓存过的请求:

//Attempttoretrievethisitemfromcache.

Cache.Entryentry=mCache.get(request.getCacheKey());

if(entry==null){

request.addMarker("cache-miss");

//Cachemiss;sendofftothenetworkdispatcher.

mNetworkQueue.put(request);

continue;

}

这里看到被缓存的请求时根据请求的cacheKey从cache中取出,如果取出的缓存为空,直接把请求放到mNetworkQueue,也就是说把请求交给了NetworkDispatcher去执行。

如果请求的缓存对象过期,同上:

//Ifitiscompletelyexpired,justsendittothenetwork.

if(entry.isExpired()){

request.addMarker("cache-hit-expired");

request.setCacheEntry(entry);

mNetworkQueue.put(request);

continue;

}

这里我们看到一个关键性的代码:

Response<?>response=request.parseNetworkResponse(

newNetworkResponse(entry.data,entry.responseHeaders));

这是什么意思呢?

Volley不仅缓存了请求本身,而且缓存了请求的响应结果,此时做的就是从缓存中取出响应的结果,这样就不用再发请求去服务器上了。

接下来,

if(!entry.refreshNeeded()){

//Completelyunexpiredcachehit.Justdelivertheresponse.

mDelivery.postResponse(request,response);

}else{

//Soft-expiredcachehit.Wecandeliverthecachedresponse,

//butweneedtoalsosendtherequesttothenetworkfor

//refreshing.

request.addMarker("cache-hit-refresh-needed");

request.setCacheEntry(entry);

//Marktheresponseasintermediate.

response.intermediate=true;

//Posttheintermediateresponsebacktotheuserandhave

//thedeliverythenforwardtherequestalongtothenetwork.

finalRequest<?>finalRequest=request;

mDelivery.postResponse(request,response,newRunnable(){

@Override

publicvoidrun(){

try{

mNetworkQueue.put(finalRequest);

}catch(InterruptedExceptione){

//Notmuchwecandoaboutthis.

}

}

});

}

如果缓存数据不需要刷新,只需要用回掉接口返回值,反之,把请求放入mNetworkQueue,等待NetworkDispatcher执行。

至此,Volley的线程模型分析告一段落,我们看到了线程组NetworkDispatcher[]和单线程CacheDispatcher通过两个BlockingQueue巧妙地实现了网络请求任务的交替轮换。

下一节Volley的缓存http://f303153041.iteye.com/blog/2281360

相关推荐

狂草 / 0评论 2015-08-18

狂草 / 0评论 2014-12-06