Volley源码解读上.docx
- 文档编号:10781879
- 上传时间:2023-02-22
- 格式:DOCX
- 页数:20
- 大小:55.58KB
Volley源码解读上.docx
《Volley源码解读上.docx》由会员分享,可在线阅读,更多相关《Volley源码解读上.docx(20页珍藏版)》请在冰豆网上搜索。
Volley源码解读上
Volley源码解读(上)
Volley框架的使用
Volley网络框架的使用方式绝大部分人都已经很熟悉了。
最简单的就是通过Volley提供的静态方法newRequestQueue(Contextcontext)来返回一个消息队列MessageQueue,然后在需要使用时将构造的网络请求消息添加到队列中去,这样就可以完成网络请求
//定义全局的请求队列
requestQueue=Volley.newRequestQueue(getApplicationContext());
//实例化一个请求,并添加到请求队列中去:
Stringurl="";
//实例化一个新的StringRequest,参数依次为:
请求方式,请求的URL,请求成功的回调接口,请求失败的回调接口。
StringRequestrequest=newStringRequest(Method.GET,url,newListener
@Override
publicvoidonResponse(Stringarg0){
Toast.makeText(MainActivity.this,arg0,Toast.LENGTH_SHORT).show();;
Log.e("successful",arg0);
}
},newResponse.ErrorListener(){
@Override
publicvoidonErrorResponse(VolleyErrorarg0){
//TODOAuto-generatedmethodstub
Toast.makeText(MainActivity.this,arg0.toString(),Toast.LENGTH_SHORT).show();
Log.e("failed",arg0.toString());
}
});
//为每一个请求设置Tag标记,便于后期对request的管理
request.setTag("testGet");
//添加到请求队列中去
MyApplication.getHttpQueues().add(request)
Volley的具体使用方式可以看这篇博文《Volley框架的使用》
Volley的源码(基于Vollley1.0.11)
在上边可以看到我们通过调用Volley提供的静态方法newRequestQueue来获取到一个消息队列,其源码其实是调用了另一个newRequestQueue方法,源码中有多个不同的newRequestQueue函数
//所有的newRequestQueue函数都是调用的该函数,传入参数依次为上下文对象,http请求栈,缓存的最大值
publicstaticRequestQueuenewRequestQueue(Contextcontext,HttpStackstack,intmaxDiskCacheBytes){
//用于缓存的文件路径
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){
}
//传入的stack为空,也就是没有自定义stack
if(stack==null){
//根据不同的SDK版本使用不同的Stack进行存储
if(Build.VERSION.SDK_INT>=9){
stack=newHurlStack();
}else{
stack=newHttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
//在构造好存储队列之后,构造网络请求
Networknetwork=newBasicNetwork(stack);
//构造请求队列
RequestQueuequeue;
if(maxDiskCacheBytes<=-1)
{
//Nomaximumsizespecified
queue=newRequestQueue(newDiskBasedCache(cacheDir),network);
}
else
{
//Diskcachesizespecified
queue=newRequestQueue(newDiskBasedCache(cacheDir,maxDiskCacheBytes),network);
}
//让队列开始工作
queue.start();
returnqueue;
}
//---下边的函数都是调用的第一个函数---
//传入两个参数
publicstaticRequestQueuenewRequestQueue(Contextcontext,intmaxDiskCacheBytes){
returnnewRequestQueue(context,null,maxDiskCacheBytes);
}
//传入两个参数
publicstaticRequestQueuenewRequestQueue(Contextcontext,HttpStackstack)
{
returnnewRequestQueue(context,stack,-1);
}
//只有一个传入参数
publicstaticRequestQueuenewRequestQueue(Contextcontext){
returnnewRequestQueue(context,null);
}
//
由此可以梳理一下调用newRequest()方法之后所发生的的操作。
首先生成了文件的缓存路径
然后判断是否自定义了stack队列,若没有定义队列,则根据SDK版本生成默认的stack,SDK大于9使用HurlStack,否则使用HttpClientStack
声明网络请求的实例
根据传入的maxDiskCacheBytes来构造请求队列
可以看到其工作流程很清晰,其中主要分为stack的创建,network的创建,和requestqueue的创建。
stack创建
//传入的stack为空,也就是没有自定义stack,创建默认的stack
if(stack==null){
//根据不同的SDK版本使用不同的Stack进行存储
if(Build.VERSION.SDK_INT>=9){
stack=newHurlStack();
}else{
stack=newHttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
默认的stack根据SDK版本的不同分为HurlStack和HttpClientStack,两者其实都是HttpStack的实现类,主要区别在于适用的SDK版本不一样,HurlStack更加适用于Android版本在2.3和更高版本,因为其内部实现是用了HttpURLConnection这个类。
而HttpClientStack适用于Android版本在2.2和更低版本(现在市面上已经没有了)。
首先来看一下低版本中使用的HttpClientStack的实现:
HttpClientStack
@Override
publicHttpResponseperformRequest(Request
>request,Map
throwsIOException,AuthFailureError{
//首先是创建http的request
HttpUriRequesthttpRequest=createHttpRequest(request,additionalHeaders);
addHeaders(httpRequest,additionalHeaders);
addHeaders(httpRequest,request.getHeaders());
onPrepareRequest(httpRequest);
//获取到request请求中的参数
HttpParamshttpParams=httpRequest.getParams();
inttimeoutMs=request.getTimeoutMs();
//TODO:
Reevaluatethisconnectiontimeoutbasedonmorewide-scale
//datacollectionandpossiblydifferentforwifivs.3G.
//请求超时机制
HttpConnectionParams.setConnectionTimeout(httpParams,5000);
HttpConnectionParams.setSoTimeout(httpParams,timeoutMs);
//将Request提交给HttpClient去执行,并将执行结果返回
returnmClient.execute(httpRequest);
}
在这里边主要有三个动作:
创建HttpRequest
封装参数
将HttpRequest提交给HttpClient去执行(在外部是传入了一个AndroidHttpClient的实例)
其实HurlStack所做的操作和HttpClientStack类似,只是在最后执行网络请求的时候HurlStack使用的是HttpURLConnection,而HttpClientStack使用HttpClient来执行任务。
接下来看一下HurlStack的具体实现:
HurlStack:
以下是HurlStack中的核心方法performRequest,实现了HttpStack接口定义的方法
@Override
publicHttpResponseperformRequest(Request
>request,Map
throwsIOException,AuthFailureError{
//根据请求来获取url地址
Stringurl=request.getUrl();
//保存请求头
HashMap
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
//如果有需要可以通过UrlRewriter接口重写url地址
if(mUrlRewriter!
=null){
Stringrewritten=mUrlRewriter.rewriteUrl(url);
if(rewritten==null){
thrownewIOException("URLblockedbyrewriter:
"+url);
}
url=rewritten;
}
//生成最终使用的url
URLparsedUrl=newURL(url);
//开启连接
HttpURLConnectionconnection=openConnection(parsedUrl,request);
//吧request中请求头的信息添加进去
for(StringheaderName:
map.keySet()){
connection.addRequestProperty(headerName,map.get(headerName));
}
//设置请求的参数
setConnectionParametersForRequest(connection,request);
//InitializeHttpResponsewithdatafromtheHttpURLConnection.
ProtocolVersionprotocolVersion=newProtocolVersion("HTTP",1,1);
intresponseCode=connection.getResponseCode();
if(responseCode==-1){
//-1isreturnedbygetResponseCode()iftheresponsecodecouldnotberetrieved.
//Signaltothecallerthatsomethingwaswrongwiththeconnection.
thrownewIOException("CouldnotretrieveresponsecodefromHttpUrlConnection.");
}
StatusLineresponseStatus=newBasicStatusLine(protocolVersion,
connection.getResponseCode(),connection.getResponseMessage());
//封装请求的结果
BasicHttpResponseresponse=newBasicHttpResponse(responseStatus);
//从connecttion中取出实体并保存在response中
response.setEntity(entityFromConnection(connection));
for(Entry
connection.getHeaderFields().entrySet()){
if(header.getKey()!
=null){
Headerh=newBasicHeader(header.getKey(),header.getValue().get(0));
response.addHeader(h);
}
}
//返回响应response
returnresponse;
}
以上这两种方式就是Volley中两种不同的请求队列的方式,在构造完stack之后就需要用构造好的stack来创建一个Netwoork实例。
构造网络请求
Networknetwork=newBasicNetwork(stack);
在下边这个方法中完成了对网络请求的发起和对返回的response的校验封装,最终返回一个NetworkResponse实例
@Override
publicNetworkResponseperformRequest(Request
>request)throwsVolleyError{
//记录请求开始的时间
longrequestStart=SystemClock.elapsedRealtime();
while(true){
//用于接收响应报文
HttpResponsehttpResponse=null;
byte[]responseContents=null;
Map
try{
//Gatherheaders.
Map
//添加缓存头,从请求中获取需要缓存的字段
addCacheHeaders(headers,request.getCacheEntry());
//调用HttpStack定义的方法来执行请求,具体使用哪种stack由当前SDK版本决定
httpResponse=mHttpStack.performRequest(request,headers);
//从之前返回的httpResponse中获取返回信息
StatusLinestatusLine=httpResponse.getStatusLine();
intstatusCode=statusLine.getStatusCode();
responseHeaders=convertHeaders(httpResponse.getAllHeaders());
//Handlecachevalidation.处理缓存的更新
if(statusCode==HttpStatus.SC_NOT_MODIFIED){
Entryentry=request.getCacheEntry();
if(entry==null){
returnnewNetworkResponse(HttpStatus.SC_NOT_MODIFIED,null,
responseHeaders,true,
SystemClock.elapsedRealtime()-requestStart);
}
//AHTTP304responsedoesnothaveallheaderfields.We
//havetousetheheaderfieldsfromthecacheentryplus
//thenewonesfromtheresponse.
//http:
//www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
entry.responseHeaders.putAll(responseHeaders);
returnnewNetworkResponse(HttpStatus.SC_NOT_MODIFIED,entry.data,
entry.responseHeaders,true,
SystemClock.elapsedRealtime()-requestStart);
}
//Handlemovedresources重定向url进行请求
if(statusCode==HttpStatus.SC_MOVED_PERMANENTLY||statusCode==HttpStatus.SC_MOVED_TEMPORARILY){
StringnewUrl=responseHeaders.get("Location");
request.setRedirectUrl(newUrl);
}
//Someresponsessuchas204sdonothavecontent.Wemustcheck.
//检查返回的response是否有内容,有的话取出保存,没有的话用byte数组填充。
if(httpResponse.getEntity()!
=null){
responseContents=entityToBytes(httpResponse.getEntity());
}else{
//Add0byteresponseasawayofhonestlyrepresentinga
//no-contentrequest.
responseContents=newbyte[0];
}
//iftherequestisslow,logit.,计算请求周期时间
longrequestLifetime=SystemClock.elapsedRealtime()-requestStart;
//用llog输出这是一次缓慢的网络请求
logSlowRequests(requestLifetime,request,responseContents,statusLine);
//如果返回的状态码小于200或者是大于299,报出异常
if(statusCode<200||statusCode>299){
thrownewIOException();
}
returnnewNetworkResponse(statusCode,responseContents,responseHeaders,false,
SystemClock.elapsedRealtime()-requestStart);
//下边就是异常的处理
}catch(SocketTimeoutExceptione){
attemptRetryOnException("socket",request,newTimeoutError());
}catch(ConnectTimeoutExceptione){
attemptRetryOnException("connection",request,newTimeoutError());
}catch(MalformedURLExceptione){
thrownewRuntimeException("BadURL"+request.getUrl(),e);
}catch(IOExceptione){
intstatusCode=0;
NetworkResponsenetworkResponse=null;
if(httpResponse!
=null){
statusCode=httpResponse.getStatusLine().getStatusCode();
}else{
thrownewNoConnectionError(e);
}
if(statusCode==HttpStatus.SC_MOVED_PERMANENTLY||
statusCode==HttpStatu
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Volley 源码 解读
![提示](https://static.bdocx.com/images/bang_tan.gif)