解析Android框架之Volley源码
作者:handsome黄 发布时间:2021-09-30 19:44:28
Volley简单使用
我这里是以依赖架包的形式 ,大家也可以以gradle的形式进行依赖。
好了,接下来上代码了.....
//获取volley的请求对象
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Log.d("MainActivity", "----->" + s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.d("MainActivity", "---volleyError-->" + volleyError);
}
});
requestQueue.add(stringRequest);
从代码可以看出,首先newRequestQueue来获取到一个请求队列,然后在将StringRequest这个请求添加到请求队列中,就可以了,就是这么简单。当然请求不值StringRequest,还有JsonObjectRequest ,ImageRequest等等但是用法都是一样的,这里就不贴代码了。Volley的简单使用就这样可以进行请求了。是不是很简单
Volley执行原理
但是这个不是本篇的重点,重点是分析一下这些是怎么执行的。先上一张图
我们先看看newRequestQueue这个内部是怎么执行的,代码一开始连续执行了几个重载方法,最后走到newRequestQueue
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException var7) {
;
}
//这里进行了一个版本的判断 2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection
if (stack == null) {
if (VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork((HttpStack)stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1) {
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
} else {
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
在这里,我们看到了一个版本判断,是不是瞬间感觉有点熟悉,没错,我们前面说的,volley2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection就是在这里进行判断的。接着看queue.start();
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
mCacheDispatcher是缓存调度线程,NetworkDispatcher是网络调度线程,而这个this.mDispatchers.length系统默认的大小为4,也就是说,在这里总共启动了5个线程在后台运行。
好了,到这里,就可以了,看源码不要每一行都弄懂,不然,出不来了。到这里就拿到了这个RequestQueue对象。回过头来看前面使用的代码
//获取volley的请求对象
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String s) {
Log.d("MainActivity", "----->" + s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.d("MainActivity", "---volleyError-->" + volleyError);
}
});
requestQueue.add(stringRequest);
我们拿到这个RequestQueue对象以后,然后就把这个请求通过add方法添加到队列中,我们看看这个add()方法是怎么执行的。
public <T> Request<T> add(Request<T> request) {
request.setRequestQueue(this);
Set var2 = this.mCurrentRequests;
synchronized(this.mCurrentRequests) {
this.mCurrentRequests.add(request);
}
request.setSequence(this.getSequenceNumber());
request.addMarker("add-to-queue");
if (!request.shouldCache()) { //如果不能缓存
this.mNetworkQueue.add(request);
return request;
} else {
Map var7 = this.mWaitingRequests;
synchronized(this.mWaitingRequests) {
String cacheKey = request.getCacheKey();
if (this.mWaitingRequests.containsKey(cacheKey)) { //判断之前是否执行过,但是还没有返回结果
Queue<Request<?>> stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList();
}
((Queue)stagedRequests).add(request);
this.mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
}
} else {
//没有的话就将请求加入缓存队列mCacheQueue,同时加入mWaitingRequests中用来做下次同样请求来时的重复判断依据
this.mWaitingRequests.put(cacheKey, (Object)null);
this.mCacheQueue.add(request);
}
return request;
}
}
}
从代码中可以看出,首先判断是否可以缓存,当然,默认是可以缓存的。如果不能缓存的话,则通过this.mNetworkQueue.add(request);将请求添加到网络请求队列中。如果可以缓存,则还会判断一次这个请求是否请求,如果执行过就就通过this.mWaitingRequests.put(cacheKey, stagedRequests);添加到mWaitingRequests队列,不在重复请求。否则就加入到缓存队列。
大体的流程是这样。现在我们看看缓存的,和网络的是怎么执行的。我们找到start()方法
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
先看CacheDispatcher,找到run()方法
public void run() {
if (DEBUG) {
VolleyLog.v("start new dispatcher", new Object[0]);
}
Process.setThreadPriority(10);
this.mCache.initialize();
while(true) {
while(true) {
while(true) {
while(true) {
try {
while(true) {
final Request<?> request = (Request)this.mCacheQueue.take(); //从缓存队列中获取到一个请求
request.addMarker("cache-queue-take");
if (request.isCanceled()) { //判断请求是否取消,如果取消了,那就将该请求finish掉
request.finish("cache-discard-canceled");
} else {
Entry entry = this.mCache.get(request.getCacheKey());
if (entry == null) {//如果从缓存中取出来的内容为空,则将请求加入到网络线程中再次请求
request.addMarker("cache-miss");
this.mNetworkQueue.put(request);
} else if (entry.isExpired()) { //如果请求过期了,则将请求加入到网络线程中再次请求
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
this.mNetworkQueue.put(request);
} else { //将数据回调到主线程
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (entry.refreshNeeded()) {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
response.intermediate = true;
this.mDelivery.postResponse(request, response, new Runnable() {
public void run() {
try {
CacheDispatcher.this.mNetworkQueue.put(request);
} catch (InterruptedException var2) {
;
}
}
});
} else {
this.mDelivery.postResponse(request, response);
}
}
}
}
} catch (InterruptedException var4) {
if (this.mQuit) {
return;
}
}
}
}
}
}
}
这里嵌套了几个循环,有点凌乱啊,但是慢慢分析的话,就会发现,其实很清晰。我在注释上面写了,这里就不重复了
我们在看看NetworkDispatcher,看看网络线程是怎么执行的。一样找到run()方法
public void run() {
Process.setThreadPriority(10);
while(true) {
long startTimeMs;
Request request;
while(true) {
startTimeMs = SystemClock.elapsedRealtime();
try {
request = (Request)this.mQueue.take(); //获取到一个请求
break;
} catch (InterruptedException var6) {
if (this.mQuit) {
return;
}
}
}
try {
request.addMarker("network-queue-take");
if (request.isCanceled()) { //如果请求取消了,则将请求finish掉
request.finish("network-discard-cancelled");
} else {//进行网络请求
this.addTrafficStatsTag(request);
NetworkResponse networkResponse = this.mNetwork.performRequest(request);
request.addMarker("network-http-complete");
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
} else {
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
if (request.shouldCache() && response.cacheEntry != null) {
this.mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
this.mDelivery.postResponse(request, response);
}
}
} catch (VolleyError var7) {
var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.parseAndDeliverNetworkError(request, var7);
} catch (Exception var8) {
VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
VolleyError volleyError = new VolleyError(var8);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.mDelivery.postError(request, volleyError);
}
}
}
代码比较多,我们直接找到NetworkResponse networkResponse = this.mNetwork.performRequest(request);这句代码,这句代码就是请求网络的代码,最核心的。performRequest是一个接口,我们看看这个performRequest()方法。Network在最开始说版本判断的时候里面有一句代码Network network = new BasicNetwork((HttpStack)stack); 从这句代码,我们可以知道BasicNetwork才是最终实现网络请求的类,我们找到performRequest方法
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while(true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map responseHeaders = Collections.emptyMap();
try {
Map<String, String> headers = new HashMap();
this.addCacheHeaders(headers, request.getCacheEntry());
httpResponse = this.mHttpStack.performRequest(request, headers);
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
if (statusCode == 304) {
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
}
entry.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(304, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
}
if (statusCode == 301 || statusCode == 302) {
String newUrl = (String)responseHeaders.get("Location");
request.setRedirectUrl(newUrl);
}
byte[] responseContents;
if (httpResponse.getEntity() != null) {
responseContents = this.entityToBytes(httpResponse.getEntity());
} else {
responseContents = new byte[0];
}
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
this.logSlowRequests(requestLifetime, request, responseContents, statusLine);
if (statusCode >= 200 && statusCode <= 299) {
return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
}
throw new IOException();
} catch (SocketTimeoutException var12) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException var13) {
attemptRetryOnException("connection", request, new TimeoutError());
} catch (MalformedURLException var14) {
throw new RuntimeException("Bad URL " + request.getUrl(), var14);
} catch (IOException var15) {
int statusCode = false;
NetworkResponse networkResponse = null;
if (httpResponse == null) {
throw new NoConnectionError(var15);
}
int statusCode = httpResponse.getStatusLine().getStatusCode();
if (statusCode != 301 && statusCode != 302) {
VolleyLog.e("Unexpected response code %d for %s", new Object[]{statusCode, request.getUrl()});
} else {
VolleyLog.e("Request at %s has been redirected to %s", new Object[]{request.getOriginUrl(), request.getUrl()});
}
if (responseContents == null) {
throw new NetworkError(networkResponse);
}
networkResponse = new NetworkResponse(statusCode, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
if (statusCode != 401 && statusCode != 403) {
if (statusCode != 301 && statusCode != 302) {
throw new ServerError(networkResponse);
}
attemptRetryOnException("redirect", request, new AuthFailureError(networkResponse));
} else {
attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
}
}
}
}
代码比较多,但是大多数代码是判断状态返回码的,不需要理会。
我们直接看httpResponse = this.mHttpStack.performRequest(request, headers);这一句代码,HttpStack这个有没有很熟悉。没有??没关系我在复制一次代码
if (stack == null) {
if (VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
还是在这个版本判断这里,这里就是HurlStack就是真正的网络请求的类了,网络请求,就是写在这个类里面的。好了,volley整个流程大概就是这样了。现在大家回过头看最初的哪一张图,是不是明了很多。
来源:https://www.cnblogs.com/huangjialin/p/9337801.html
![](https://www.aspxhome.com/images/zang.png)
![](https://www.aspxhome.com/images/jiucuo.png)
猜你喜欢
- 一.WebSocket简单介绍WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-d
- 实践过程效果代码public partial class Form1 : Form{ public Form1()
- 直接来,ResponseDemo1代码,get请求到post请求,重定向到ResponseDemo2我的虚拟目录为ResponseDemo1
- 线程的两种创建方式及优劣比较1、通过实现Runnable接口线程创建(1).定义一个类实现Runnable接口,重写接口中的run()方法。
- Java常用类库Math类Math包含用于执行基本数字运算的方法,例如基本指数,对数,平方根和三角函数一、Field SummaryModi
- 本文实例为大家分享了java制作简单验证码的具体代码,供大家参考,具体内容如下在这里我们需要用到java的画笔工具,所以我们需要导入以下包i
- 字符串每隔4位加空格今天弄了个银行卡识别功能,回显的时候想要将银行卡号每四位加一个空格,这样核对卡号会方便很多,这里记录一下1.正则表达式实
- 本文实例讲述了Java实现批量导入excel表格数据到数据库中的方法。分享给大家供大家参考,具体如下:1、创建导入抽象类package co
- 方法的返回值为什么要有带返回值的方法呢?调用处拿到方法的结果之后,才能根据结果进行下一步操作带返回值方法的定义和调用:如果在调用处,要根据方
- Java的接口和抽象类深入理解对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。
- MVC中,一般的情况下,使用IDE工具帮我们生成的代码,在路由注册的时候:public static void RegisterRoutes
- 前言以下为本文要记录的大概内容:Java基础案例:两只老虎、三个和尚、考试奖励以下是本篇文章正文内容,仅供参考一、案例1:两只老虎1.题目:
- 什么是耦合性耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、
- 1. 概述为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。2. 模式中的角色2.1 外
- 一、文件存储特点:openFileInput()和openFileOutput()读取设备上的文件。优点:适用于存储大量的数据,可以存储图片
- 一、创建maven项目我使用的是汉化的idea可以选择原型,我这里没有选择输入项目名称,完成创建二、配置tomcat选择运行编辑配置点加号找
- 本文实例为大家分享了UnityShader实现运动模糊的具体代码,供大家参考,具体内容如下原理:像素的当前帧的NDC坐标(x,y
- 我们很容易能想到,可以用递归来实现汉诺塔游戏。因为要将n(n>1)个盘子从“源”柱子移到“目标”柱子,我们要先把n-1个盘子从“源”柱
- Json的简介JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个
- 在LINUX上部署带有JAR包的JAVA项目首先eclipse上要装上一个小插件,叫做Fat Jar点击Fat Jar红框里选上主类点击Ne