在学习的android 系统源码时 发现了volley 这个库,于是就学习学习.
1.volley 官网使用说明地址:volley 从官网就知道volley 简单的使用,优点和缺点
优点:
- Automatic scheduling of network requests. //自动处理网络请求
- Multiple concurrent network connections.// 适用多并发
- Transparent disk and memory response caching with standard HTTP cache coherence. //对请求应答数据进行磁盘和内存中进行缓存
- Support for request prioritization.// 支持优先级 请求 优先级越高优先处理
- Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.//可以取消request 实际上只是调用reqeust.cancel()方法把回调方法置空.也可以跟其他组件生命周期进行绑定
- Ease of customization, for example, for retry and backoff.//可以重连 默认类不做重连 需要自己实现
- Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.//便捷的通过异步请求获取网络数据并分发的ui 线程更新数据
缺点:
- Volley is not suitable for large download or streaming operations, since Volley holds all responses in memory during parsing. For large download operations;// 不适用大数据的处理 因为解析应答数据是在内存进行的说白了就是会消耗大量内存.
- volley 默认 开五个线程时处理请求,一个缓存线程和四个网络线程 ,所以volley 定位是网络请求频繁的,且应答内容小的.如果网络请求不频繁那需要配置线程数量不然造成资源浪费.
使用
final RequestQueue requestQueue = Volley.newRequestQueue(this);
findViewById(R.id.btn_Request).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
StringRequest request = new StringRequest(Request.Method.GET, "https://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.i("tag", error.getMessage());
}
});
requestQueue.add(request);
}
});
//代码很烂不规范 只是用来分析流程不喜 勿喷
2. 首先用使用Volley 来创建请求队列对象,中间会创建处理缓存对象,处理网络请求对象并开启死循环线程处理,三个集合来存放请求队列.代码如下:
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
network = new BasicNetwork(new HurlStack());
} else {
.....
} catch (NameNotFoundException e) {
}
network =
new BasicNetwork(
new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
network = new BasicNetwork(stack);
}
return newRequestQueue(context, network);
}
//没用其他的删除 都是9版本之后吧 判断stack 处理网络请求对象是否为空 为空就用HurlStack
BasicNetWork 只是代理 stack 对象 真正做网络请求的事HurlStack
BasicNetWork关键方法:
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
List<Header> responseHeaders = Collections.emptyList();
try {
// Gather headers.
Map<String, String> additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
//这里是做网络请求方法
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
//获取响应码 来判断请求结果是怎么样的 来进行不同的处理
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
// Handle cache validation. 服务器数据是否修改过 一般都图片或者大的数据进行标识
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
.....
}
// Some responses such as 204s do not have content. We must check.
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
//这个把流读取 存放到byte数组中, 所以不适合对大数据进行处理 不然耗内存 和造成内存抖动
responseContents =
inputStreamToBytes(inputStream, httpResponse.getContentLength());
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
responseContents = new byte[0];
}
// if the request is slow, log it.
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusCode);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
return new NetworkResponse(
statusCode,
responseContents,
/* notModified= */ false,
SystemClock.elapsedRealtime() - requestStart,
responseHeaders);
} catch (SocketTimeoutException e) {
//这里就是进行网络重新连接请求方法 默认空实现
attemptRetryOnException("socket", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
........
}
}
而HurlStack 实现就比较简单 这里代码就不贴出来了
3.add 方法调用之后怎么就自动 处理网络请求了呢:
public <T> Request<T> add(Request<T> request) {
// Tag the request as belonging to this queue and add it to the set of current requests.
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// Process requests in the order they are added.
//使用原子类进行自加 如果优先级相同就是fifo 如果优先级高就会往前移动进行插入
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
// If the request is uncacheable, skip the cache queue and go straight to the network.
// 默认true 也就是说设置为false 可以不走读缓存这个步骤
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}
从上面代码看来只是对请求添加到请求队列中啊 怎么就自动处理了呢?
那还得从newRequestQueue 说起
private static RequestQueue newRequestQueue(Context context, Network network) {
//缓存路径
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();//关键方法
return queue;
}
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();
// Create network dispatchers (and corresponding threads) up to the pool size.默认4个
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher =
new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
CacheDispatcher 和NetworkDispatcher 继承Thread 类那么我们只要看 run 方法就行了
CacheDispatcher.run:
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
//读取之前的缓存数据到内存中或者创建路径
mCache.initialize();
//做死循环
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
Thread.currentThread().interrupt();
return;
}
VolleyLog.e(
"Ignoring spurious interrupt of CacheDispatcher thread; "
+ "use quit() to terminate it");
}
}
}
private void processRequest() throws InterruptedException {
// Get a request from the cache triage queue, blocking until
// at least one is available.
这里就是能自动处理的原因. 因为使用的是PriorityBlockingQueue 类. take没有元素时堵塞直到add 方法把元素添加进来 ,就然后就进行读取缓存操作.这是生产_消费模式
final Request<?> request = mCacheQueue.take();
进行读取缓存操作 ,当内存没有缓存或者内容过期就把请求添加 网络请求队列中.NetworkDispatcher 实现原理跟这个是一样的,所以不用说了.当请求成功或者失败 会调用finish 把这个请求从总的请求队列中移除
processRequest(request);
}
4.回调调用 其实回调方式实现也很简单就是通过handler 把Runnable 分发到主线程执行 并调用回调.实现在 ExecutorDelivery类中
5.这里的流程就是 创建队列时会创建缓存线程和网络处理线程 并启动,没有请求时这些线程时堵塞着的,当add 一个请求时缓存线程就会得到这个请求并处理当,当内存没有缓存或者内容过期就交给网络线程处理.请求完后解析响应体进行回调.官网的流程图: