(一)基本使用
- 1,添加依赖
compile 'com.mcxiaoke.volley:library:1.0.19'
- 2,创建请求队列
RequestQueue queue=Volley.newRequestQueue(this);
- 3,创建请求
JsonObjectRequest request=new JsonObjectRequest(url, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
Log.e("success",jsonObject.toString());
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
- 4,将请求添加到请请队列
queue.add(request);
- 5,volley的缺点
5.1,在BasicNetwork中判断了statusCode(statusCode < 200 || statusCode > 299),如何符合条件直接抛出IOException(),不够合理,导致401等其他状态抛出IOException
5.2,不适合获取数据量大的文件
5.3,线程没有很好的管理,4个网络线程只是放入到一个数组里面
5.4,现在都用retrofit或者OKHttputils,特别是retrofit,自带json解析
(二)源码解析
1,在创建RequestQueue时,会判断,如果安卓版本大于2.3,就调用HttpUrlConnection的HurlStack,否则调用HttpClient的HttpClientStack,
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
/**
* 根据不同的系统版本号实例化不同的请求类,如果版本号小于9,用HttpClient
* 如果版本号大于9,用HttpUrlConnection
*/
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
//把实例化的stack传递进BasicNetwork,实例化Network
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
//实例化RequestQueue类
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
//调用RequestQueue的start()方法
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
2,可以创建各种请求,比如StringRequest,JsonRequest,ImageRequest等等
3在调用add()方法将request添加到请求队列RequesuQueue时,通过request.shouldCache()来判断是否可以缓存,不能缓存就将请求添加到网络请求队列中;如果能缓存,就判断之前是否有执行相同的请求且还没有结果返回的,如果有的话,就将此请求加入waitingRequesu队列,不再重复请求,没有的话就将此请求加入缓存队列 .
public <T> Request<T> add(Request<T> request) {
//标记当前请求,表示这个请求由当前RequestQueue处理
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// /获得当前请求的序号
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
//如果请求不能缓存,直接添加到网络请求队列,默认是可以缓存
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// 锁定当前代码块,只能一条线程执行
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
//是否有相同请求正在处理,
if (mWaitingRequests.containsKey(cacheKey)) {
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<Request<?>>();
}
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
//没有相同的请求,那么把请求放进mWaitingRequests(一个hashmap集合)中,同时也放进mCacheQueue缓存队列中
//这代表这个请求已经开始在缓存线程中运行了
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
4,磁盘缓存默认是5m
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
public class DiskBasedCache implements Cache {
/** Map of the Key, CacheHeader pairs */
private final Map<String, CacheHeader> mEntries =
new LinkedHashMap<String, CacheHeader>(16, .75f, true);
/** Total amount of space currently used by the cache in bytes. */
private long mTotalSize = 0;
/** The root directory to use for the cache. */
private final File mRootDirectory;
/** The maximum size of the cache in bytes. */
private final int mMaxCacheSizeInBytes;
/** Default maximum disk usage in bytes. */
private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
/** High water mark percentage for the cache */
private static final float HYSTERESIS_FACTOR = 0.9f;
/** Magic number for current version of cache file format. */
private static final int CACHE_MAGIC = 0x20150306;
/**
* Constructs an instance of the DiskBasedCache at the specified directory.
* @param rootDirectory The root directory of the cache.
* @param maxCacheSizeInBytes The maximum size of the cache in bytes.
*/
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {
mRootDirectory = rootDirectory;
mMaxCacheSizeInBytes = maxCacheSizeInBytes;
}
/**
* Constructs an instance of the DiskBasedCache at the specified directory using
* the default maximum cache size of 5MB.
* @param rootDirectory The root directory of the cache.
*/
public DiskBasedCache(File rootDirectory) {
this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);
}
5,默认开启了5个线程,4个网络调度线程NetworkDispatch,1个缓存调度线程CacheDispatch.
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// 创建网络线程,默认长度就是核心线程的数量,4个
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
6,Volley分为3类线程:主线程,缓存调度线程(默认1个),网络调度线程(默认4个);
6.1根据优先级将请求添加到缓存队列
6.2缓存调度线程,从缓存队列中取出1个请求
6.3如果找到该请求的缓存响应,就直接读取缓存的响应并解析,最后将解析的响应传递到主线程;
6.4若请求丢失,则通过网络调度线程从网络队列中轮训取出请求,;
6.5取出后,发送http请求,解析响应数据,存入缓存,最后将解析的响应传递到主线程
借鉴:刘望舒的进阶之光