简单实例

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. 【Java学习】调用ByteBuffer.getInt()方法得到808464432

    调用ByteBuffer.getInt()方法遇到的奇怪错误 最近在参加阿里的中间件比赛,中间用到了RocketMQ的思想,并且主要集中在使用NIO来读写文件.其中遇到了一个很蛋疼的问题,想了半天想不 ...

  2. javascript中Date对象的应用

    前面的话 简易日历作为javascript中Date对象的常见应用,用途较广泛.本文将详细说明简易日历的实现思路 效果演示 HTML说明 使用type=number的两个input分别作为年和月的输入 ...

  3. PHP视频教程 字符串处理函数(三)

    字符串替换函数: str_replace() 替换字符串或数组元素,区分大小,第四个参数可选用于统计替换次数. str_ireplace() 不区分大小写替换 字符串函数比较 strcmp()比较字符 ...

  4. 可以在GitHub或者码云里 直接搜索 项目 比如 哔哩哔哩

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha Search · 哔哩哔哩 哔哩哔哩 · 搜索 - 码云 还有就是 以前的项目 可以不要 ...

  5. Palindromic Tree 回文自动机-回文树 例题+讲解

    回文树,也叫回文自动机,是2014年被西伯利亚民族发明的,其功能如下: 1.求前缀字符串中的本质不同的回文串种类 2.求每个本质不同回文串的个数 3.以下标i为结尾的回文串个数/种类 4.每个本质不同 ...

  6. UVA11468 Substring --- AC自动机 + 概率DP

    UVA11468 Substring 题目描述: 给定一些子串T1...Tn 每次随机选择一个字符(概率会给出) 构造一个长为n的串S,求T1...Tn不是S的子串的概率 直接把T1...Tn建成AC ...

  7. [SDOI2017]数字表格 --- 套路反演

    [SDOI2017]数字表格 由于使用markdown的关系 我无法很好的掌控格式,见谅 对于这么简单的一道题竟然能在洛谷混到黑,我感到无语 \[\begin{align*} \prod\limits ...

  8. Djangio笔记

    django图解 新创建一个项目后的目录层级

  9. hihocoder155周 任务分配

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定 N 项任务的起至时间( S1, E1 ), ( S2, E2 ), ..., ( SN, EN ), 计算最少需要多 ...

  10. Swify闭包

    闭包:是字包含的匿名函数代码块,可以做为表达式.函数参数和函数返回值,闭包表达式的运算结果是一种函数类型.类似于 C# Lambda 表达式. 闭包表达式: {(参数列表)->返回类型 in 语 ...