您的位置:首页 > 产品设计 > UI/UE

Volley源码学习笔记_RequestQueue和BasicNetWork

2017-06-07 17:38 337 查看

1.开始

Volley也只是听过没用过,新接的项目里面请求用的是Volley,只能赶鸭子上架的看了些简单的使用。现在理解下源码。(ps:这里不涉及有关图片相关的部分pps:理解不对的地方请指出,灰常感谢)

2.Volley的使用

关于Volley的使用,比较简洁的。

//首先创建请求队列
RequestQueue requestQueue = Volley.newRequestQueue(Context);
//创建一个request
Request request=new Request() {...};
//将request添加到请求队列中
requestQueue.add(request);


下面根据上面的三行代码,来一步步的看相关的实现源码。

3.RequestQueue

我们先看 new RequestQueue的代码,它只传入了一个Context

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;
}


以上代码包含的内容还是很多的。主要是先根据VERSION.SDK_INT

来判断使用什么网络连接请求类。然后实例化一个BasicNetWork来进行网络交互请求。 然后创建一个请求队列,传入一个DiskBasedCache,一个BasicNetwork,最后队列start。下面先看一下RequestQueue的构造函数。

public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {

//下面这5个有的是直接在外面初始化的
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);
}


从下往上, this(cache, network, 4);这是的4就是线程数目,记得之前好像还是可以自己输入的现在默认是4个。这里有一个ExecutorDelivery,主要作用就是传递消息(response),可以看到它的实现要传递一个Handler。这个后期再看。下面看一下RequestQueue的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();
}

}


从上面可以看出,只要new了一个RequestQueue那么就会开启1个缓存线程,4个网络请求

线程。这就意味着一次最多只能并发5个线程,如果缓存线程没有命中,那么最多并发4个网

络请求线程。NetworkDispatcher基本就是从队列中获取请求,然后请求网络数据

(BasicNetWork)同时更新到UI线程。(ExecutorDelivery)。

既然是队列了,那他是如何addRequest的呢?

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.
//先记着一个队列序号,先入先出
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");

// If the request is uncacheable, skip the cache queue and go straight to the network.
//请求不用缓存就加入到网络请求队列中,但是这个值默认是true
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}

//根据key值判断请求是否已经在重复请求队列,但是会发现最终都是要添加到这个队列里面的
// Insert request into stage if there's already a request with the same cache key in flight.
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey)) {
// There is already a request in flight. Queue up.
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<>();
}
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
//添加到缓存队列里面去
mCacheQueue.add(request);
}
return request;
}
}


RequestQueue的add方法,从这里我们可以看到四个参数 mWaitingRequests ,mCurrentRequests ,mCacheQueue ,mNetworkQueue。分别是重复请求队列,当前请求或者等待请求集合,缓存队列,网络请求队列,这里重复队列就是一个Map集合,key是cacheKey,就是getUrl。mCacheQueue ,mNetworkQueue是一个优先级队列 。根据优先级来执行,同等优先级是无序的。

当mCacheQueue或者mNetworkQueue利用add方法添加请求之后,在运行的线程就会接收到请求(Cache线程接收到请求,会将相应的请求提那家到mNetworkQueue,这样在请求线程中就可以处理请求队列中的请求),从而去处理相对应的请求,最后将处理的结果由mDelivery来发送到主线程进行更新。

BasicNetWork的具体作用有:

1)对于已经有缓存的请求,添加其头部信息,如下:

private void addCacheHeaders(Map<String, String> headers, Entry entry) {
if(entry != null) {
if(entry.etag != null) {
headers.put("If-None-Match", entry.etag);
}

if(entry.serverDate > 0L) {
Date refTime = new Date(entry.serverDate);
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
}

}
}


2)调用 HttpStack 对象去网络中获取数据,返回httpResonse 对象。

httpResponse = this.mHttpStack.performRequest(request, e);


3)根据状态编码来返回不同的NetworkResponse对象

如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。

if(networkResponse1 == 304) {
return new NetworkResponse(304, request.getCacheEntry().data, responseHeaders1, true);
}
...

long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
this.logSlowRequests(requestLifetime, request, responseContents1, statusCode2);
if(networkResponse1 >= 200 && networkResponse1 <= 299) {
return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false);
}
...
NetworkResponse networkResponse = null;
if(httpResponse == null) {
throw new NoConnectionError(var15);
}

int statusCode1 = httpResponse.getStatusLine().getStatusCode();
VolleyLog.e("Unexpected response code %d for %s", new Object[]{Integer.valueOf(statusCode1), request.getUrl()});
if(responseContents == null) {
throw new NetworkError(networkResponse);
}

networkResponse = new NetworkResponse(statusCode1, (byte[])responseContents, responseHeaders, false);
if(statusCode1 != 401 && statusCode1 != 403) {
throw new ServerError(networkResponse);
}


4)BasicNetwork实现了重试的机制

如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。

private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError {
RetryPolicy retryPolicy = request.getRetryPolicy();
int oldTimeout = request.getTimeoutMs();

try {
retryPolicy.retry(exception);
} catch (VolleyError var6) {
request.addMarker(String.format("%s-timeout-giveup [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)}));
throw var6;
}

request.addMarker(String.format("%s-retry [timeout=%s]", new Object[]{logPrefix, Integer.valueOf(oldTimeout)}));
}


下面看一下3的内容

//具体代码就不贴了
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
....
}


public interface Network {
NetworkResponse performRequest(Request<?> var1) throws VolleyError;
}


BasicNetwork是Network 的实现类。。Network 的方法只有一个performRequest(),参数是Request。用来获取网络请求到的数据,然后在NetworkDispatcher中被解析后通过ExecutorDelivery将请求结果传到UI线程。

这里有一段代码:

byte[] responseContents1;
if(httpResponse.getEntity() != null) {
responseContents1 = this.entityToBytes(httpResponse.getEntity());
} else {
responseContents1 = new byte[0];
}
if(networkResponse1 >= 200 && networkResponse1 <= 299) {
return new NetworkResponse(networkResponse1, responseContents1, responseHeaders1, false);
}


这是请求到数据的时候,然后在状态码返回200-299之间的时候创建一个NetworkResponse对象并将其data设置为获取到内容。除了在状态码304的时候,还有一个地方也创建了NetworkResponse对象。这里的responseContents是开始创建的一个空对象。

networkResponse = new NetworkResponse(statusCode1, (byte[])responseContents, responseHeaders, false);
if(statusCode1 != 401 && statusCode1 != 403) {
throw new ServerError(networkResponse);
}


以上。不对的地方麻烦大家指出,非常感谢。

参考

[1].http://blog.csdn.net/linmiansheng/article/details/22653841

[2].http://blog.csdn.net/mr_liabill/article/details/50241543

[3].http://f303153041.iteye.com/blog/2281350
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: