在2013年Google I/O大会上推出了一个新的网络通信框架Volley。Volley既可以访问网络取得数据,也可以加载图片,并且在性能方面也进行了大幅度的调整,它的设计目标就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。
Volley网络请求队列
Volley请求网络都是基于请求队列的,开发者只要把请求放在请求队列中就可以了。
请求队列会依次进行请求,一般情况下,一个应用程序如果网络请求没有特别频繁则完全可以只有一个请求队列(对应Application),如果非常多或其他情况,则可以是一个Activity对应一个网络请求队列,这就要看具体情况了,首先创建队列:
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest的用法
StringRequest返回的数据是String类型的,我们查看下StringRequest的源码:
public class StringRequest extends Request<String> {
private final Listener<String> mListener;
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
}
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(0, url, listener, errorListener);
}
...
}
试着用GET方法来请求百度:
//创建请求队列
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.i("TAG", response);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
});
//将请求添加在请求队列中
mQueue.add(mStringRequest);
//要添加网络权限
JsonRequest的用法
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
JsonObjectRequest mJsonObjectRequest = new JsonObjectRequest(Request.Method.POST,
"http://api.1-blog.com/biz/bizserver/article/list.do",
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d("TAG", response.toString());
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
}
);
//将请求添加在请求队列中
mQueue.add(mJsonObjectRequest);
收到的是json,可用Gson去获取对应的对象
源码分析
结构图
RequestQueue 请求队列
创建 RequestQueue
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
深入:
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (HttpStack)null);
}
↓↓↓↓↓↓↓↓↓↓↓↓↓
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
return newRequestQueue(context, stack, -1);
}
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
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 packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + packageInfo.versionCode;
} catch (NameNotFoundException var7) {
// 忽略异常
}
// 第四步:如果未提供 HttpStack,则根据 Android 版本选择使用 HurlStack 或 HttpClientStack
if (stack == null) {
if (VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
// 第五步:使用 HttpStack 创建 BasicNetwork
BasicNetwork network = new BasicNetwork((HttpStack) stack);
// 第六步:使用 DiskBasedCache 创建 RequestQueue
RequestQueue queue;
if (maxDiskCacheBytes <= -1) {
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
} else {
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
// 第七步:启动 RequestQueue
queue.start();
// 第八步:返回创建的 RequestQueue
return queue;
}
主要看第四步和第七步:
- 如果android版本大于等于2.3则调用基于HttpURLConnection的HurlStack(),否则就调用基于HttpClient的HttpClientStack()
- 创建了RequestQueue,调用了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(缓存调度器线程),然后在循环中调用了**NetworkDispatcher(网络调度线程)**的start()
方法
默认情况下mDispatchers.length为4,默认开启了4个网络调度线程,也就是说有5个线程在后台运行并等待请求的到来。
然后再使用过程中我们创建各种的Request,并调用RequestQueue的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 var8 = this.mWaitingRequests;
synchronized(this.mWaitingRequests) {
String cacheKey = request.getCacheKey();
// 判断是否已经有相同CacheKey的请求正在发送中,若有则将当前请求加入等待队列中,不再重复请求
if (this.mWaitingRequests.containsKey(cacheKey)) {
Object 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 {
// 若没有相同CacheKey的请求正在发送中,则将请求加入缓存队列中,并将其添加到等待集合中
this.mWaitingRequests.put(cacheKey, (Object) null);
this.mCacheQueue.add(request);
}
return request;
}
}
}
通过判断request.shouldCache()
,来先判断是否可以缓存,默认是可以缓存的
如果不能缓存,则将请求添加到网络请求队列中,如果能缓存就判断之前是否有执行相同的请求且还没有返回结果的,如果有的话将此请求加入mWaitingRequests
队列,不再重复请求;没有的话就将请求加入缓存队列mCacheQueue
,同时加入mWaitingRequests
中用来做下次同样请求来时的重复判断依据。
当将请求添加到网络请求队列或者缓存队列时,这时在后台的网络调度线程和缓存调度线程轮询各自的请求队列发现有请求任务则开始执行,
CacheDispatcher缓存调度线程
缓存队列mCacheQueue
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 {
//获取缓存队列中的一个请求
final Request e = (Request)this.mCacheQueue.take();
e.addMarker("cache-queue-take");
//如果请求取消了则将请求停止掉
if(e.isCanceled()) {
e.finish("cache-discard-canceled");
} else {
//查看是否有缓存的响应
Entry entry = this.mCache.get(e.getCacheKey());
//如果缓存响应为空,则将请求加入网络请求队列
if(entry == null) {
e.addMarker("cache-miss");
this.mNetworkQueue.put(e);
//判断缓存响应是否过期
} else if(!entry.isExpired()) {
e.addMarker("cache-hit");
//对数据进行解析并回调给主线程
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
e.addMarker("cache-hit-parsed");
if(!entry.refreshNeeded()) {
this.mDelivery.postResponse(e, response);
} else {
e.addMarker("cache-hit-refresh-needed");
e.setCacheEntry(entry);
response.intermediate = true;
this.mDelivery.postResponse(e, response, new Runnable() {
public void run() {
try {
CacheDispatcher.this.mNetworkQueue.put(e);
} catch (InterruptedException var2) {
;
}
}
});
}
} else {
e.addMarker("cache-hit-expired");
e.setCacheEntry(entry);
this.mNetworkQueue.put(e);
}
}
} catch (InterruptedException var4) {
if(this.mQuit) {
return;
}
}
}
}
}
}
}
static {
DEBUG = VolleyLog.DEBUG;
}
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()) {
request.finish("network-discard-cancelled");
} else {
this.addTrafficStatsTag(request);
//请求网络
NetworkResponse e = this.mNetwork.performRequest(request);
request.addMarker("network-http-complete");
if(e.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
} else {
Response volleyError1 = request.parseNetworkResponse(e);
request.addMarker("network-parse-complete");
if(request.shouldCache() && volleyError1.cacheEntry != null) {
//将响应结果存入缓存
this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
this.mDelivery.postResponse(request, volleyError1);
}
}
} 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);
}
}
}
网络调度线程也是从队列中取出请求并且判断是否被取消了,如果没取消就去请求网络得到响应并回调给主线程。
获取网络响应
请求网络时调用this.mNetwork.performRequest(request)
用来返回网络响应,这个mNetwork是一个接口,实现它的类是BasicNetwork,我们来看看BasicNetwork的performRequest()
方法:
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
Object responseContents = null;
Map responseHeaders = Collections.emptyMap();
try {
HashMap e = new HashMap();
this.addCacheHeaders(e, request.getCacheEntry());
httpResponse = this.mHttpStack.performRequest(request, e); // 开始发起网络请求
StatusLine statusCode1 = httpResponse.getStatusLine();
int networkResponse1 = statusCode1.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // 将响应头信息转换为Map形式
if (networkResponse1 == 304) { // 如果服务器返回304,表示请求的资源没有变化,可以使用缓存的响应
Entry requestLifetime2 = request.getCacheEntry();
if (requestLifetime2 == null) { // 如果没有缓存条目,则直接返回304响应
return new NetworkResponse(304, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
}
requestLifetime2.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(304, requestLifetime2.data, requestLifetime2.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
}
} catch (IOException var12) {
// 处理网络请求异常
}
}
}
回调给主线程
再回到网络调度线程,请求网络后,会将响应结果存在缓存中,如果响应结果成功则调用this.mDelivery.postResponse(request, volleyError1)
来回调给主线程。
Delivery的postResponse()
方法:
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));
}
↓↓↓↓↓↓↓ResponseDeliveryRunnable
private class ResponseDeliveryRunnable implements Runnable {
private final Request mRequest;
private final Response mResponse;
private final Runnable mRunnable;
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
this.mRequest = request; // 存储请求对象
this.mResponse = response; // 存储响应对象
this.mRunnable = runnable; // 存储可运行对象
}
public void run() {
if (this.mRequest.isCanceled()) { // 如果请求已被取消
this.mRequest.finish("canceled-at-delivery"); // 标记请求为取消状态
} else {
if (this.mResponse.isSuccess()) {
this.mRequest.deliverResponse(this.mResponse.result); //***如果响应成功,传递响应结果给请求对象进行处理
} else {
this.mRequest.deliverError(this.mResponse.error); //不成功 传递错误信息给请求对象进行处理
}
if (this.mResponse.intermediate) { // 如果响应为中间响应
this.mRequest.addMarker("intermediate-response"); // 添加标记表示为中间响应
} else {
this.mRequest.finish("done"); // 标记请求为完成状态
}
if (this.mRunnable != null) { // 如果存在可运行对象
this.mRunnable.run(); // 执行可运行对象的操作
}
}
}
}
看第25行的this.mRequest.deliverResponse(this.mResponse.result)
这个就是实现Request抽象类必须要实现的方法,例如StringRequest,用来传递响应结果
public class StringRequest extends Request<String> {
private final Listener<String> mListener;
public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
}
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(0, url, listener, errorListener);
}
protected void deliverResponse(String response) {
this.mListener.onResponse(response);
}
...
}
在deliverResponse()方法中调用了this.mListener.onResponse(response)
,最终将response回调给了Response.Listener的onResponse()
方法。
即我们一般在app里面写的写法:文章来源:https://www.toymoban.com/news/detail-830657.html
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
//.....
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
...
}
});
//将请求添加在请求队列中
mQueue.add(mStringRequest);
文章来源地址https://www.toymoban.com/news/detail-830657.html
到了这里,关于【网络编程】Volley使用与源码分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!