Volley已经封装了常用格式数据的请求, 例如image, json, string等;
在此对image的请求过程跟踪一下.
首先从调用处开始:
public class MainActivity extends Activity implements Listener<Bitmap>, ErrorListener{
private ImageView mImage = null;
private RequestQueue mQueue = null;
private ImageRequest mImageRequest = null;
private String mUrl = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mImage = (ImageView) findViewById(R.id.imageview);
mImage.setMaxWidth(720);
mImage.setMaxHeight(1080);
mQueue = Volley.newRequestQueue(this);
mUrl = "http://pp.myapp.com/ma_pic2/0/shot_11673554_20452929_3_1423106639/550";
mImageRequest = new ImageRequest(mUrl, this, mImage.getWidth() , mImage.getHeight(), Config.ARGB_8888, this);
mQueue.add(mImageRequest);
}
@Override
public void onResponse(Bitmap bitmap) {
mImage.setImageBitmap(bitmap);
}
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.setTag("MainActivity");
VolleyLog.e("", "");
}
}
主要是两步:
1. 实例化一个ImageRequest对象;
2. 添加到Volley的请求队列;
实例化ImageRequest对象时需要传入几个参数
new ImageRequest(url, listener, maxWidth, maxHeight, decodeConfig, errorListener)
第一个是图片的链接;
第二个是Response.Listener;
第三个和第四个分别时图片最大的宽和高;
第五个是图片的编码;
第六个是Response.ErrorListener;
RequestQueue的实例化:
RequestQueue mQueue = Volley.newRequestQueue(context);
在Volley类中返回一个queue对象
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, null);
}
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(
packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See:
// http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(
AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(network);
queue.start();
return queue;
}
可以看到, 返回的RequestQueue也是volley自定义的, 在queue实例化之后马上就start了.
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create network dispatchers (and corresponding threads) up to the pool
// size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(
mNetworkQueue, mNetwork, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
不断地从queue中取出请求,并分发出去.
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
public RequestQueue(Network network, int threadPoolSize,
ResponseDelivery delivery) {
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
public RequestQueue(Network network, int threadPoolSize) {
this(network, threadPoolSize, new ExecutorDelivery(new Handler(
Looper.getMainLooper())));
}
public RequestQueue(Network network) {
this(network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
默认的线程池大小为4
将请求添加到queue的过程如下;
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();
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");
mNetworkQueue.add(request);
return request;
}
实际上最终的请求是存放在PriorityBlockingQueue中
request.setSequence(getSequenceNumber());是给该请求分配一个优先级, 其中getSequenceNumber()就是得到一个递增的数, 也就是说, 请求是按添加顺序进行执行的,前提是同一类请求,不同类的请求的优先级是不一样的.
上面说到了,queue会不断的分发请求, 将请求添加到queue后,
NetworkDispatcher networkDispatcher = new NetworkDispatcher(
mNetworkQueue, mNetwork, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
public class NetworkDispatcher extends Thread
启动线程,
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request<?> request;
try {
// Take a request from the queue.
request = mQueue.take();
} catch (Exception e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
addTrafficStatsTag(request);
// Perform the network request.
NetworkResponse networkResponse = mNetwork
.performRequest(request);
request.addMarker("network-http-complete");
// Parse the response here on the worker thread.
Response<?> response = request
.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime()
- startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime()
- startTimeMs);
mDelivery.postError(request, volleyError);
}
}
}
层层封装,最终实现网络请求的地方
NetworkResponse networkResponse = mNetwork.performRequest(request);
@Override
public NetworkResponse performRequest(Request<?> request)
throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
// Gather headers.
Map<String, String> headers = new HashMap<String, String>();
httpResponse = mHttpStack.performRequest(request, headers);
System.out.println(httpResponse.getEntity().toString());
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// Some responses such as 204s do not have content. We must
// check.
if (httpResponse.getEntity() != null) {
responseContents = entityToBytes(httpResponse.getEntity());
} 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,
statusLine);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
return new NetworkResponse(statusCode, responseContents,
responseHeaders, SystemClock.elapsedRealtime()
- requestStart);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {
attemptRetryOnException("connection", request,
new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode,
request.getUrl());
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode,
responseContents, responseHeaders,
SystemClock.elapsedRealtime() - requestStart);
if (statusCode == HttpStatus.SC_UNAUTHORIZED
|| statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth", request,
new AuthFailureError(networkResponse));
} else {
throw new ServerError(networkResponse);
}
} else {
throw new NetworkError(networkResponse);
}
}
}
}
在这个方法里面还是对数据的请求进行了封装
httpResponse = mHttpStack.performRequest(request, headers);
@Override
public HttpResponse performRequest(Request<?> request,
Map<String, String> additionalHeaders) throws IOException,
AuthFailureError {
HttpUriRequest httpRequest = createHttpRequest(request,
additionalHeaders);
addHeaders(httpRequest, additionalHeaders);
addHeaders(httpRequest, request.getHeaders());
onPrepareRequest(httpRequest);
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
// data collection and possibly different for wifi vs. 3G.
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
return mClient.execute(httpRequest);
}
终于找到执行请求的地方, mHttpStack是从哪里来的呢?
往上找发现, 在实例化queue的时候
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
这一句在上面已经贴出来了的.
我是把volley的cache部分剥离了, 所以贴出来的代码可能跟volley源码有些不同, 但是网络请求部分是没有改动的.
至此,整个请求的过程已经分析完了, 其实还有很多细节值得学习, volley既然是google开源出来的, 肯定融入了很多智慧. 这顿大餐还需慢慢咀嚼!