当前位置:首页 > 商业/管理/HR > 质量控制/管理 > Android开发——Volley源码解析
Android开发——Volley源码解析0.前言其实写这篇文章只为一个目的,虽然Volley用起来很爽,但是面试官问你人家内部是怎么实现呢,没看过源码的话,在面试官眼里你和一个拿着一本Volley使用手册的高中生没啥区别。还是那句话说得好,会用一回事,深入理解又是另一回事了。1.Volley源码解析1.1Volley入口Volley首先获取到的是RequestQueue实例。源码中则直接调用了newRequestQueue方法。[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicstaticRequestQueuenewRequestQueue(Contextcontext){returnnewRequestQueue(context,null);}publicstaticRequestQueuenewRequestQueue(Contextcontext,HttpStackstack){FilecacheDir=newFile(context.getCacheDir(),DEFAULT_CACHE_DIR);StringuserAgent=volley/0;try{StringpackageName=context.getPackageName();PackageInfoinfo=context.getPackageManager().getPackageInfo(packageName,0);userAgent=packageName+/+info.versionCode;}catch(NameNotFoundExceptione){}if(stack==null){if(Build.VERSION.SDK_INT=9){stack=newHurlStack();}else{stack=newHttpClientStack(AndroidHttpClient.newInstance(userAgent));}}Networknetwork=newBasicNetwork(stack);RequestQueuequeue=newRequestQueue(newDiskBasedCache(cacheDir),network);queue.start();returnqueue;}从上面源码中可以看到,判断传入的stack为空,则根据系统版本去创建一个HttpStack对象,大于等于9的,则创建一个HurlStack的实例(内部使用HttpURLConnection),否则就创建一个HttpClientStack的实例(内部使用HttpClient)。之所以这样做是因为:(1)HttpURLConnection在小于9的版本中存在调用imputStream.close()会导致连接池失败的BUG,相对来说HTTPClient在小于9的系统版本中有较少的BUG。(2)而在大于等于9的版本中,HttpURLConnection的实现有更多的优点,API更简单,体积更小,有压缩功能以及4.0以后加入的缓存机制(如本地缓存、304缓存、服务器缓存)。创建好了HttpStack之后将其作为参数创建了一个Network对象,接着又根据Network对象创建了一个RequestQueue对象,并调用它的start()方法进行启动,然后将该实例返回。1.2RequestQueue.start()[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicvoidstart(){stop();mCacheDispatcher=newCacheDispatcher(mCacheQueue,mNetworkQueue,mCache,mDelivery);mCacheDispatcher.start();for(inti=0;imDispatchers.length;i++){//默认循环4次NetworkDispatchernetworkDispatcher=newNetworkDispatcher(mNetworkQueue,mNetwork,mCache,mDelivery);mDispatchers[i]=networkDispatcher;networkDispatcher.start();}}这里CacheDispatcher和NetworkDispatcher都是继承自Thread的,也就是说当调用了Volley.newRequestQueue(context)之后,一个缓存线程和四个网络请求线程会一直在后台运行,并等待网络请求的到来。1.3RequestQueue.add()既然上面已经迫不及待等待网络请求的到来了,那么是时候将我们的Request添加进队列了。[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicTRequestTadd(RequestTrequest){//Tagtherequestasbelongingtothisqueueandaddittothesetofcurrentrequests.request.setRequestQueue(this);synchronized(mCurrentRequests){mCurrentRequests.add(request);}//Processrequestsintheordertheyareadded.request.setSequence(getSequenceNumber());request.addMarker(add-to-queue);//Iftherequestisuncacheable,skipthecachequeueandgostraighttothenetwork.if(!request.shouldCache()){mNetworkQueue.add(request);returnrequest;}//Insertrequestintostageifthere'salreadyarequestwiththesamecachekeyinflight.synchronized(mWaitingRequests){StringcacheKey=request.getCacheKey();if(mWaitingRequests.containsKey(cacheKey)){//Thereisalreadyarequestinflight.Queueup.QueueRequest?stagedRequests=mWaitingRequests.get(cacheKey);if(stagedRequests==null){stagedRequests=newLinkedListRequest?();}stagedRequests.add(request);mWaitingRequests.put(cacheKey,stagedRequests);if(VolleyLog.DEBUG){VolleyLog.v(RequestforcacheKey=%sisinflight,puttingonhold.,cacheKey);}}else{//Insert'null'queueforthiscacheKey,indicatingthereisnowarequestin//flight.mWaitingRequests.put(cacheKey,null);mCacheQueue.add(request);}returnrequest;}}在第11行的时候会判断当前的请求是否可以缓存,默认情况下是可以缓存的,除非主动调用了Request的setShouldCache(false)方法来不允许其进行缓存。因此默认情况下会将该请求加入到缓存队列,否则直接加入网络请求队列。下面看看缓存线程中的run方法。1.4CacheDispatcher中的run()[java]viewplaincopy在CODE上查看代码片派生到我的代码片publicvoidrun(){if(DEBUG)VolleyLog.v(startnewdispatcher);Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//Makeablockingcalltoinitializethecache.mCache.initialize();while(true){try{//Getarequestfromthecachetriagequeue,blockinguntil//atleastoneisavailable.finalRequest?request=mCacheQueue.take();request.addMarker(cache-queue-take);//Iftherequesthasbeencanceled,don'tbotherdispatchingit.if(request.isCanceled()){request.finish(cache-discard-canceled);continue;}//Attempttoretrievethisitemfromcache.Cache.Entryentry=mCache.get(request.getCacheKey());if(entry==null){request.addMarker(cache-miss);//Cachemiss;sendofftothenetworkdispatcher.mNetworkQueue.put(request);continue;}//Ifitiscompletelyexpired,justsendittothenetwork.if(entry.isExpired()){request.addMarker(cache-hit-expired);request.setCacheEntry(entry);mNetworkQueue.put(request);continue;}//Wehaveacachehit;parseitsdatafordeliverybacktotherequest.request.addMarker(cache-hit);Response?response=request.parseNetworkResponse(newNetworkResponse(entry.data,entry.responseHeaders));request.addMarker(cache-hit-parsed);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.mDelivery.postResponse(request,response,newRunnable(){@Overridepubli
本文标题:Android开发——Volley源码解析
链接地址:https://www.777doc.com/doc-5500761 .html