简单实例

Volley是一个封装HttpUrlConnection和HttpClient的网络通信框架,集AsyncHttpClient和Universal-Image-Loader的长处于了一身。既能够像AsyncHttpClient一样很easy地进行HTTP通信,也能够像Universal-Image-Loader一样轻松载入并缓存下载的图片。Volley在性能方面也进行了大幅度的调整,它的设计目标就是进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比方说下载文件等,Volley的表现就会比較糟糕。从以下这个简单的实例来研究一下源代码。

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);
StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String s) {
tv.setText(s);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) { }
});
mQueue.add(stringRequest);

流程

1、以静态工厂形式实例化一个RequestQueue对象

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);

  • 首先看一下RequestQueue这个类:
public class RequestQueue {
private AtomicInteger mSequenceGenerator;
private final Map<String, Queue<Request>> mWaitingRequests;
private final Set<Request> mCurrentRequests;
private final PriorityBlockingQueue<Request> mCacheQueue;
private final PriorityBlockingQueue<Request> mNetworkQueue;
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
private final Cache mCache;
private final Network mNetwork;
private final ResponseDelivery mDelivery;
private NetworkDispatcher[] mDispatchers;
private CacheDispatcher mCacheDispatcher; public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
this.mSequenceGenerator = new AtomicInteger();
this.mWaitingRequests = new HashMap();
this.mCurrentRequests = new HashSet();
this.mCacheQueue = new PriorityBlockingQueue();
this.mNetworkQueue = new PriorityBlockingQueue();
this.mCache = cache;
this.mNetwork = network;
this.mDispatchers = new NetworkDispatcher[threadPoolSize];
this.mDelivery = delivery;
} public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));
} public RequestQueue(Cache cache, Network network) {
this(cache, network, 4);
}
...
}

从构造函数可知,mWaitingRequests、mCurrentRequests、mCacheQueue、mNetworkQueue是以组合形式实例化,后两者是堵塞队列;而mCache、mNetwork是以聚合形式注入;mDelivery默认也是组合形式new ExecutorDelivery(new Handler(Looper.getMainLooper())))实例化。

  • newRequestQueue方法:
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (HttpStack)null);
}
 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), "volley");
String userAgent = "volley/0"; try {
String network = context.getPackageName();
PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
userAgent = network + "/" + queue.versionCode;
} catch (NameNotFoundException var6) {
;
} if(stack == null) {
if(VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
} BasicNetwork network1 = new BasicNetwork((HttpStack)stack);
RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);
queue1.start();
return queue1;
}

结合RequestQueue类可知,实例化的RequestQueue对象,注入了new DiskBasedCache(cacheDir)network1。缓存方式默认是磁盘缓存。NetWork对象会依据系统版本号。选用不同的Http通信方式。

  • 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();
} }

CacheDispatcher和NetworkDispatcher都是继承Thread类。所以这种方法生成一条缓存分发线程,和四条网络线程。

  • CacheDispatcher类继承Thread类。全部參数都是聚合形式注入,看下关键的run()方法。因为代码较长。这里不贴了,分段分析下几个比較重要的方法
while(true){
...
Request e = (Request)this.mCacheQueue.take();
...
}

首先任务是一个死循环,因为mCacheQueue是个堵塞队列,所以将不断地从堵塞队列读取Request


 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-expired");
e.setCacheEntry(entry);
this.mNetworkQueue.put(e);
} else {
e.addMarker("cache-hit");
Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
...
}

推断请求是否有缓存。假设没有或者缓存已经过期。将请求放到网络队列里面。否则找到缓存。则进行以下的操作。


Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));

parseNetworkResponse是Request类的抽象方法,我们进去StringRequest看下:

protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
} return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}

可看作是对网络下载的数据进行解析处理。然后返回。


this.mDelivery.postResponse(e, response);

最后进行这一步,mDelivery是在RequestQueue里面实例化后注入CacheDispatcher的。详细的实例化对象:new ExecutorDelivery(new Handler(Looper.getMainLooper()))。看下ExecutorDelivery类。找到postResponse方法。

    public void postResponse(Request<?> request, Response<?> response) {
this.postResponse(request, response, (Runnable)null);
} public void postResponse(Request<? > request, Response<? > response, Runnable runnable) {
...
this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));
}

继续往下看

private class ResponseDeliveryRunnable implements Runnable {
...
run(){
...
if(this.mResponse.isSuccess()) {
this.mRequest.deliverResponse(this.mResponse.result);
}
...
}
...
}

deliverResponse方法相同是Request类的抽象方法,我们进去StringRequest看下

    protected void deliverResponse(String response) {
this.mListener.onResponse(response);
}

就一句回调


  • NetworkDispatcher类相同继承Thread类,其分析过程和CacheDispatcher差点儿相同,重要的相同是以下几步:

1、从网络堵塞队列读取请求,request = (Request)this.mQueue.take();

2、网络下载,NetworkResponse e = this.mNetwork.performRequest(request);(假设是CacheDispatcher这一步就是缓存推断)

3、处理下载后的数据,Response response = request.parseNetworkResponse(e);

3、对处理后的数据进行回调,this.mDelivery.postResponse(e, response)。


2、实例化一个Request对象

StringRequest stringRequest = new StringRequest (url,listener,errorListener);

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);
} protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException var4) {
parsed = new String(response.data);
} return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}

由第一个分析步骤能够知道,这个Request主要就是进行两个操作,也就是重写两个方法。

  1. protected abstract Response<T> parseNetworkResponse(NetworkResponse var1);对下载后的数据进行解析处理。
  2. protected abstract void deliverResponse(T var1);最后回调操作这个数据的方法。

所以构造函数仅需下载地址和回调操作的方法。


3、调用queue.add()方法

 if(!request.shouldCache()) {
this.mNetworkQueue.add(request);
return request;
}

假设不须要缓存就直接加入到网络队列里面,Request有个比較重要的布尔字段mShouldCache,默认是用来推断是否要进行磁盘缓存的。


this.mCacheQueue.add(request);

否则将其加入到缓存队列,这种方法上面也会进行一些当前队列和等待队列的防反复的操作。


小结

框架部分:

1、实例化一个RequestQueue对象,开启一条缓存线程和默认的四条网络线程,线程不断地从缓存堵塞队列和网络堵塞队列里面读取请求;

2、假设缓存线程从缓存队列里面读取的请求已经缓存过,则解析数据回调操作方法。否则将其加入到网络队列;

3、假设缓存线程从缓存队列里面读取的请求没有缓存过,则加入到网络队列。

4、网络线程从网络堵塞队列不断读取请求,读到请求后则由封装好的HttpStack对象进行网络下载处理、下载后回调对数据处理的方法,处理后回调操作数据的方法。

客户部分:

1、实例化一个请求对象。在请求对象里面重写处理网络下载后的数据的方法。和操作处理后的数据的方法。

2、将请求对象加入到请求队列。请求须要缓存则会被加入到分配到缓存队列,不须要则被加入到网络队列。


之前看过一个问题。说框架和库有什么不同,高人答曰:框架是他调用你代码,库是你调用他代码。

优秀的框架拓展性是如此之强,尽管自己远没那个能力,只是也算开了眼界!

Android:Volley源代码解析的更多相关文章

  1. [转] Android Volley完全解析(一),初识Volley的基本用法

    版权声明:本文出自郭霖的博客,转载必须注明出处.   目录(?)[-] Volley简介 下载Volley StringRequest的用法 JsonRequest的用法   转载请注明出处:http ...

  2. Android Volley完全解析

    1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行H ...

  3. Android xUtils3源代码解析之网络模块

    本文已授权微信公众号<非著名程序猿>原创首发,转载请务必注明出处. xUtils3源代码解析系列 一. Android xUtils3源代码解析之网络模块 二. Android xUtil ...

  4. Android Volley完全解析(三),定制自己的Request

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17612763 经过前面两篇文章的学习,我们已经掌握了Volley各种Request ...

  5. Android Volley完全解析(二),使用Volley加载网络图片

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482165 在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法. ...

  6. Android Volley全然解析(四),带你从源代码的角度理解Volley

    版权声明:本文出自郭霖的博客,转载必须注明出处. https://blog.csdn.net/sinyu890807/article/details/17656437 转载请注明出处:http://b ...

  7. volley源代码解析(七)--终于目的之Response&lt;T&gt;

    在上篇文章中,我们终于通过网络,获取到了HttpResponse对象 HttpResponse是android包里面的一个类.然后为了更高的扩展性,我们在BasicNetwork类里面看到.Volle ...

  8. [转]Android Volley完全解析(四),带你从源码的角度理解Volley

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17656437 经过前三篇文章的学习,Volley的用法我们已经掌握的差不多了,但是 ...

  9. Android EventBus源代码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  10. Android DiskLruCache 源代码解析 硬盘缓存的绝佳方案

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/47251585: 本文出自:[张鸿洋的博客] 一.概述 依然是整理东西.所以最近 ...

随机推荐

  1. GeneXus项目启动

    使用GeneXus产品开发项目时,在开始,有一些属性我会经常改一下.我现在使用的GeneXus版本是GeneXus U3,由于在做手机应用的开发,所以一般使用最新的版本,老外那边差不多两个月会有一个u ...

  2. scrapy抓取拉勾网职位信息(六)——反爬应对(随机UA,随机代理)

    上篇已经对数据进行了清洗,本篇对反爬虫做一些应对措施,主要包括随机UserAgent.随机代理. 一.随机UA 分析:构建随机UA可以采用以下两种方法 我们可以选择很多UserAgent,形成一个列表 ...

  3. java 读入文件 FileInputStream

    package com.mkyong.io; import java.io.File; import java.io.FileInputStream; import java.io.IOExcepti ...

  4. zTree通过指定ID找到节点并选中

    zTree = $.fn.zTree.getZTreeObj("treeDemo");//treeDemo界面中加载ztree的div var node = zTree.getNo ...

  5. Problem G: 切煎饼

    Description 王小二自夸刀工不错,有人放一张大的圆煎饼在砧板上,问他:饼不允许离开砧板,切100刀最多能切多少块? Input 多组测试数据,每组输入1个整数,代表切的刀数 Output 每 ...

  6. 24.最优布线问题(kruskal算法)

    时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 查看运行结果 题目描述 Description 学校需要将n台计算机连接起来,不同的2台计算机之间的连接费用 ...

  7. python开发_re和counter

    python中re和counter的结合,可以实现以下的功能: 1.获取字符串或者文件中的单词组 2.对单词组进行统计 下面是我做的demo 运行效果: ======================= ...

  8. [转][译][Android基础]Android Fragment之间的通信

    2014-2-14 本篇文章翻译自Android官方的培训教程,我也是初学者,觉得官方的Training才是最好的学习材料,所以边学边翻译,有翻译不好的地方,请大家指正. 如果我们在开发过程中为了重用 ...

  9. Educational Codeforces Round 11 D. Number of Parallelograms 暴力

    D. Number of Parallelograms 题目连接: http://www.codeforces.com/contest/660/problem/D Description You ar ...

  10. leetcode644. Maximum Average Subarray II

    leetcode644. Maximum Average Subarray II 题意: 给定由n个整数组成的数组,找到长度大于或等于k的连续子阵列,其具有最大平均值.您需要输出最大平均值. 思路: ...