Android:Volley源代码解析
简单实例
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主要就是进行两个操作,也就是重写两个方法。
protected abstract Response<T> parseNetworkResponse(NetworkResponse var1);
对下载后的数据进行解析处理。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]Android视频录制命令screenrecord
- [Android Pro] 超能RecyclerView组件使用
- [Android Pro] 横竖屏切换时,禁止activity重新创建,android:configChanges="keyboardHidden|orientation" 不起作用
- [Android Traffic] 使用缓存来避免重复的下载
- 【黑马Android】(02)短信发送器/布局演示/android下单位/android下Junit/保存数据/android下权限/xml解析和序列化
- Android API之android.os.Parcelable
- android 之断点续传详解三部曲之[一] → 多任务下载
- sqlite升级--浅谈Android数据库版本升级及数据的迁移
- 《android开发艺术探索》读书笔记(十五)--Android性能优化
- 墙裂推荐,Android 开发百大框架源码精编解析
- Android性能优化:Github下载超10万次的360°全方面性能调优指南(含内存优化、布局优化、实战解析等)
- Android修行手册 - LinearLayout线性布局全解析
- android 系统查看 pid和uid找到对应的应用
- Android【报错】. lang。android.app ClassCastException。SharedPreferencesImpl不能被强制转换为android.content.Shared
- Android报错提示:Failed to resolve: com.android.support.constraint:constraint-layout:1.1.3
- Android TextView根据textsize计算TextView的宽度和高度
- 【Android 异步操作】Handler 机制 ( Android 提供的 Handler 源码解析 | Handler 构造与消息分发 | MessageQueue 消息队列相关方法 )
- Android的Bitmap和BitmapDrawable类解析-android学习之旅(六十)
- Android ViewDragHelper全然解析 自己定义ViewGroup神器
- 【Android界面实现】信息更新小红点显示——自己定义控件BadgeView的使用介绍
- android解析XML总结(SAX、Pull、Dom三种方式) <转载>
- 【Android源码解析】一篇就够“路由、网络层、UI层、通信层....百大框架”源码解析,阿里P8神级之作
- Android Studio的报错提示:android.content.res.Resources$NotFoundException: Resource ID #0xfffffe6c
- android如何查看cpu的占用率和内存泄漏