本文仅对Volley中关于Http Request部分的一些简单用例做解析

源码目录树

首先,用脚本生成了该项目源码的目录树:

[android]┗━[volley]    ┣━AuthFailureError.java    ┣━Cache.java    ┣━CacheDispatcher.java    ┣━DefaultRetryPolicy.java    ┣━ExecutorDelivery.java    ┣━InternalUtils.java    ┣━Network.java    ┣━NetworkDispatcher.java    ┣━NetworkError.java    ┣━NetworkResponse.java    ┣━NoConnectionError.java    ┣━ParseError.java    ┣━RedirectError.java    ┣━Request.java    ┣━RequestQueue.java    ┣━Response.java    ┣━ResponseDelivery.java    ┣━RetryPolicy.java    ┣━ServerError.java    ┣━TimeoutError.java    ┣━[toolbox]    ┃  ┣━AndroidAuthenticator.java    ┃  ┣━Authenticator.java    ┃  ┣━BasicNetwork.java    ┃  ┣━ByteArrayPool.java    ┃  ┣━ClearCacheRequest.java    ┃  ┣━DiskBasedCache.java    ┃  ┣━HttpClientStack.java    ┃  ┣━HttpHeaderParser.java    ┃  ┣━HttpStack.java    ┃  ┣━HurlStack.java    ┃  ┣━ImageLoader.java    ┃  ┣━ImageRequest.java    ┃  ┣━JsonArrayRequest.java    ┃  ┣━JsonObjectRequest.java    ┃  ┣━JsonRequest.java    ┃  ┣━NetworkImageView.java    ┃  ┣━NoCache.java    ┃  ┣━PoolingByteArrayOutputStream.java    ┃  ┣━RequestFuture.java    ┃  ┣━StringRequest.java    ┃  ┗━Volley.java    ┣━VolleyError.java    ┗━VolleyLog.java

可以看出,Volley源码放置得较为杂乱,不同功能模块的类并没有归到不同的包中。相比之下UIL的源码结构较为规范和合理。

从常用case入手,推断其项目架构

官网上给出的最简单的使用例子如下所示:

final TextView mTextView = (TextView) findViewById(R.id.text);...// 1. 新建一个QueueRequestQueue queue = Volley.newRequestQueue(this); String url ="http://www.google.com";// 2. 新建一个Request,写好listenerStringRequest stringRequest = new StringRequest(Request.Method.GET, url,             new Response.Listener() {    @Override    public void onResponse(String response) {        // Display the first 500 characters of the response string.        mTextView.setText("Response is: "+ response.substring(0,500));    }}, new Response.ErrorListener() {    @Override    public void onErrorResponse(VolleyError error) {        mTextView.setText("That didn't work!");    }});// 3. 将Request放到Queue里面执行queue.add(stringRequest); 

结合下面这张图:

我们可以大致了解Volley的使用方法(见注释)和内部结构。下面就这个usecase展开进行源码级别的简述。

Volley类

Volley类提供了4个静态方法来方便用户新建Queue。其中:

public static RequestQueue newRequestQueue(Context context) {    return newRequestQueue(context, null);}

一句最终会调用:

// 传入 context,stack=null,maxDiskCacheBytes=-1public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);    String userAgent = "volley/0"; //1. 设置userAgent    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) { //2. 选择用哪个httpclient            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;    if (maxDiskCacheBytes <= -1)    {        // No maximum size specified        queue = new RequestQueue(new DiskBasedCache(cacheDir), network); //3. 新建Queue    }    else    {        // Disk cache size specified        queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);    }    queue.start();// 4. 传入Queue    return queue;}

值得注意的是:

  1. Volley会根据SDK的version来决定使用java.net.HttpURLConnection(Build.VERSION.SDK_INT >= 9)还是org.apache.http.client.HttpClient

  2. 新建Queue后,Queue马上会被start。

  3. stack类负责发送request(com.android.volley.Request)和获取response(org.apache.http.HttpResponse),network类负责分析和处理response,包装成NetworkResponse(com.android.volley.NetworkResponse)。

我们首先忽略掉network相关的细节,看一下queue的实现和request的调度策略。

RequestQueue

先来看一下RequestQueue的构造方法:

public RequestQueue(Cache cache, Network network) {    this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);}

调用:

public RequestQueue(Cache cache, Network network, int threadPoolSize) {    this(cache, network, threadPoolSize,            new ExecutorDelivery(new Handler(Looper.getMainLooper())));}

这里出现了一个新面孔ExecutorDelivery,根据字面意思可以猜测它是负责将请求的结果分发到主线程上,或者在主线程上执行回调(listener)。继续调用:

public RequestQueue(Cache cache, Network network, int threadPoolSize,        ResponseDelivery delivery) {    mCache = cache;    mNetwork = network;    mDispatchers = new NetworkDispatcher[threadPoolSize];    mDelivery = delivery;}

这里又出现了一个新面孔NetworkDispatcher。留意到threadPoolSize这个数组长度参数的字面意义,结合上面的Volley架构图,猜想NetworkDispatcher是一个work thread,循环等待并通过network执行在Queue上的request。

RequestQueue被实例化后,便调用其start()方法:

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.    for (int i = 0; i < mDispatchers.length; i++) {        NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,                mCache, mDelivery);        mDispatchers[i] = networkDispatcher;        networkDispatcher.start();    }}

相应地有:

public void stop() {    if (mCacheDispatcher != null) {        mCacheDispatcher.quit();    }    for (int i = 0; i < mDispatchers.length; i++) {        if (mDispatchers[i] != null) {            mDispatchers[i].quit();        }    }}

这里的逻辑很简单:

  1. 开始之前停止所有旧的任务(即interrupt所有worker thread)。

  2. 启动一个负责cache的worker thread。

  3. 启动n个负责network的worker thread。

  4. worker thread开始不断地等待来自Queue的request。

Request

接下来执行queue.add(stringRequest); ,一个request被加入到queue中,代码如下所示:

public  Request add(Request 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"); // marker用来指示request当前的状态,实际上是用来打log    // If the request is uncacheable, skip the cache queue and go straight to the network.    if (!request.shouldCache()) {        mNetworkQueue.add(request);        return request;    }    // 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> 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;    }}

这里的逻辑是:

  1. 对新加进来的request进行一些设置。

  2. 如果不需要cache,那么把request直接加到network queue中。

  3. 根据key检查request是否正在执行。如果是,则将其放入到waiting链表中。猜想当request完成的时候会调用某个方法将key在waiting链表中删除,然后依次执行waiting的request。如果否,则将其加入cache queue中。

CacheDispatcher

假设该uri访问是第一次执行,那么对应的request会被放到cache queue中。cache worker thread(cache dispatcher)发现cache queue中存在request,会马上将其dequeue并执行。我们来看一下CacheDispatcher的run方法:

public class CacheDispatcher extends Thread {    ...    private final Cache mCache; // 一开始传入了“new DiskBasedCache(cacheDir)”    ...    public void quit() {        mQuit = true;        interrupt();    }    @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();        Request<?> request;        while (true) {            // release previous request object to avoid leaking request object when mQueue is drained.            request = null; //确保最后一个request做完后能及时回收内存。            try {                // Take a request from the queue.                request = mCacheQueue.take(); // 堵塞            } catch (InterruptedException e) {                // We may have been interrupted because it was time to quit.                if (mQuit) {                    return;  // 退出点                }                continue;            }            try {                request.addMarker("cache-queue-take");                // If the request has been canceled, don't bother dispatching it.                if (request.isCanceled()) {                    request.finish("cache-discard-canceled");                    continue;                }                // miss cache则直接将request放到network queue中                Cache.Entry entry = mCache.get(request.getCacheKey());                 if (entry == null) {                    request.addMarker("cache-miss");                    // Cache miss; send off to the network dispatcher.                    mNetworkQueue.put(request);                    continue;                }                // cache 过期了,直接将request放到network queue中                if (entry.isExpired()) {                     request.addMarker("cache-hit-expired");                    request.setCacheEntry(entry);                    mNetworkQueue.put(request);                    continue;                }                // 将cache中的data包装成一个response                request.addMarker("cache-hit");                Response<?> response = request.parseNetworkResponse(                         new NetworkResponse(entry.data, entry.responseHeaders));                request.addMarker("cache-hit-parsed");                if (!entry.refreshNeeded()) {                    // cache不需要刷新,直接将response交给delivery                    mDelivery.postResponse(request, response);                } else {                    // cache需要刷新。现将旧的内容返回,同时将request放进network queue。                    request.addMarker("cache-hit-refresh-needed");                    request.setCacheEntry(entry);                    // Mark the response as intermediate.                    response.intermediate = true;                    // Post the intermediate response back to the user and have                    // the delivery then forward the request along to the network.                    final Request<?> finalRequest = request;                    mDelivery.postResponse(request, response, new Runnable() {                         @Override                        public void run() {                            try {                                mNetworkQueue.put(finalRequest);                            } catch (InterruptedException e) {                                // Not much we can do about this.                            }                        }                    });                }            } catch (Exception e) {                VolleyLog.e(e, "Unhandled exception %s", e.toString());            }        }    }}

接下来看一下mDelivery.postResponse这个方法。

ExecutorDelivery

从上文得知,mDelivery是一个ExecutorDelivery的实例(在新建RequestQueue时传入)。

ExecutorDelivery的初始化代码如下所示:

public ExecutorDelivery(final Handler handler) {    // Make an Executor that just wraps the handler.    mResponsePoster = new Executor() { // java.util.concurrent.Executor;        @Override        public void execute(Runnable command) {            handler.post(command);        }    };}

关于java.util.concurrent.Executor可以看这篇文章,这里就不展开了。

postResponse代码如下所示:

@Overridepublic void postResponse(Request<?> request, Response<?> response, Runnable runnable) {    request.markDelivered(); //标记为已分发    request.addMarker("post-response");    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); // 在初始化时传入的handler中执行ResponseDeliveryRunnable}

ResponseDeliveryRunnable是ExecutorDelivery的一个子类,负责根据request的不同结果调用对应的listener方法:

@SuppressWarnings("rawtypes")private class ResponseDeliveryRunnable implements Runnable {        private final Request mRequest;    private final Response mResponse;    private final Runnable mRunnable;    public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {        mRequest = request;        mResponse = response;        mRunnable = runnable;    }        @SuppressWarnings("unchecked")    @Override    public void run() { // 在主线程中执行        // If this request has canceled, finish it and don't deliver.        if (mRequest.isCanceled()) {            mRequest.finish("canceled-at-delivery"); // 会调用 RequestQueue的finish方法            return;        }        // Deliver a normal response or error, depending.        if (mResponse.isSuccess()) {            mRequest.deliverResponse(mResponse.result); //调用 listener的onResponse(response)        } else {            mRequest.deliverError(mResponse.error);        }        // If this is an intermediate response, add a marker, otherwise we're done        // and the request can be finished.        if (mResponse.intermediate) {            mRequest.addMarker("intermediate-response");        } else {            mRequest.finish("done");        }        // If we have been provided a post-delivery runnable, run it.        if (mRunnable != null) {            mRunnable.run();        }   }}

接下来我们回头看看NetworkDispatcher对network queue的处理。

NetworkDispatcher

NetworkDispatcher的源码如下所示:

public class NetworkDispatcher extends Thread {        private final Network mNetwork; // BasicNetwork实例    ...        private final BlockingQueue> mQueue; // network queue      ...         public void quit() {        mQuit = true;        interrupt();    }    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)    private void addTrafficStatsTag(Request<?> request) { // 方便统计Volley的网络流量        ...    }    @Override    public void run() {        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        Request<?> request;        while (true) {            long startTimeMs = SystemClock.elapsedRealtime();             // release previous request object to avoid leaking request object when mQueue is drained.            request = null;            try {                //1. 堵塞读取network queue中的request                request = mQueue.take();             } catch (InterruptedException 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);                //2. 在network对象中堵塞执行request                NetworkResponse networkResponse = mNetwork.performRequest(request);                 request.addMarker("network-http-complete");                // If the server returned 304 AND we delivered a response already,                // we're done -- don't deliver a second identical response.                if (networkResponse.notModified && request.hasHadResponseDelivered()) { // 304表示资源未被修改                    request.finish("not-modified");                    continue;                }                //3. 将NetworkResponse转成Response                Response<?> response = request.parseNetworkResponse(networkResponse);                 request.addMarker("network-parse-complete");                // Write to cache if applicable.                // TODO: Only update cache metadata instead of entire record for 304s.                if (request.shouldCache() && response.cacheEntry != null) {                    // 4. Response放到cache中                    mCache.put(request.getCacheKey(), response.cacheEntry);                    request.addMarker("network-cache-written");                }                //5. 通过Delivery回调结果                request.markDelivered();                mDelivery.postResponse(request, response);            } catch (VolleyError volleyError) {                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);                parseAndDeliverNetworkError(request, volleyError);            } catch (Exception e) {                VolleyLog.e(e, "Unhandled exception %s", e.toString());                VolleyError volleyError = new VolleyError(e);                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);                mDelivery.postError(request, volleyError);            }        }    }    private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {        error = request.parseNetworkError(error);        mDelivery.postError(request, error);    }}

NetworkDispatcher的处理流程和CacheDispatcher差不多,见注释。TrafficStats的介绍可以看这里。

上述代码的关键在于mNetwork.performRequest(request)request.parseNetworkResponse(networkResponse)这两个调用。

Network

Network是一个接口,只有一个performRequest(Request<?> request)方法:

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

本文例子中Network的实现类是BasicNetwork:

public class BasicNetwork implements Network {    protected static final boolean DEBUG = VolleyLog.DEBUG;    private static int SLOW_REQUEST_THRESHOLD_MS = 3000;    private static int DEFAULT_POOL_SIZE = 4096;    protected final HttpStack mHttpStack;    protected final ByteArrayPool mPool;    public BasicNetwork(HttpStack httpStack) {        // If a pool isn't passed in, then build a small default pool that will give us a lot of        // benefit and not use too much memory.        this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));    }    ...}

注意到BasicNetwork的两个关键的成员:mHttpStack和mPool,和对apache依赖:

import org.apache.http.Header;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.HttpStatus;import org.apache.http.StatusLine;

可我们先来看一下performRequest()的执行流程:

public NetworkResponse performRequest(Request<?> request) throws VolleyError {    long requestStart = SystemClock.elapsedRealtime();    while (true) {        // 依赖 org.apache.http.HttpResponse        HttpResponse httpResponse = null;        byte[] responseContents = null;        Map responseHeaders = Collections.emptyMap();        try {            // 1. 生成header            Map headers = new HashMap();            addCacheHeaders(headers, request.getCacheEntry());            // 2. 通过httpstack发起请求。注意‘发起请求’这个动作不在request中进行,request只是保存着请求的信息。            httpResponse = mHttpStack.performRequest(request, headers);            // 3. 获得请求结果的一些信息            StatusLine statusLine = httpResponse.getStatusLine();            int statusCode = statusLine.getStatusCode();            responseHeaders = convertHeaders(httpResponse.getAllHeaders());            // 4. 通过statusCode(304)来判断是否可以直接使用cache            if (statusCode == HttpStatus.SC_NOT_MODIFIED) {                Entry entry = request.getCacheEntry();                if (entry == null) {                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,                            responseHeaders, true,                            SystemClock.elapsedRealtime() - requestStart);                }                // 从cache中取出data,返回新的NetworkResponse                entry.responseHeaders.putAll(responseHeaders);                return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,                        entry.responseHeaders, true,                        SystemClock.elapsedRealtime() - requestStart);            }                        // 5. 通过statusCode通过判断是否需要重定向            if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {                String newUrl = responseHeaders.get("Location");                request.setRedirectUrl(newUrl);            }                        // 6. 取出reponse中的data,为字节数组            // Some responses such as 204s do not have content.  We must check.            if (httpResponse.getEntity() != null) {              // 通过entityToBytes从outputstream中读取数据,throws IOException              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, false,                    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) {            // 7. 如果entityToBytes方法throw了IOException            int statusCode = 0;            NetworkResponse networkResponse = null;            if (httpResponse != null) {                statusCode = httpResponse.getStatusLine().getStatusCode();            } else {                throw new NoConnectionError(e);            }            if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||                     statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {                VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());            } else {                VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());            }            // 如果reponseContent有数据            if (responseContents != null) {                networkResponse = new NetworkResponse(statusCode, responseContents,                        responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);                // 那么根据statusCode执行重试                if (statusCode == HttpStatus.SC_UNAUTHORIZED ||                        statusCode == HttpStatus.SC_FORBIDDEN) {                    attemptRetryOnException("auth",                            request, new AuthFailureError(networkResponse));                } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||                             statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {                    attemptRetryOnException("redirect",                            request, new RedirectError(networkResponse));                } else {                    // TODO: Only throw ServerError for 5xx status codes.                    throw new ServerError(networkResponse);                }            } else {                throw new NetworkError(e);            }        }    }}

attemptRetryOnException()代码如下所示:

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 e) {        request.addMarker(                String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout));        throw e;    }    request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout));}

RetryPolicy是一个接口:

public interface RetryPolicy {    public int getCurrentTimeout();    public int getCurrentRetryCount();    public void retry(VolleyError error) throws VolleyError;}

如没有特殊指定,request中的RetryPolicy为DefaultRetryPolicy,其retry方法实现如下:

public void retry(VolleyError error) throws VolleyError {    mCurrentRetryCount++;    mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);    if (!hasAttemptRemaining()) {        throw error;    }}

如果还没超出重试次数上限,那么不会抛出异常,并返回到performRequest()的while循环中。接下来分析一下BaseNetwork的entityToBytes()方法:

private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {    // 1. 新建PoolingByteArrayOutputStream    PoolingByteArrayOutputStream bytes =            new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());    byte[] buffer = null;    try {        InputStream in = entity.getContent();        if (in == null) {            throw new ServerError();        }        // 2. 在字节池中取出1024字节buffer        buffer = mPool.getBuf(1024);        int count;        // 3. 从entity的inputStream中读出数据到buffer        while ((count = in.read(buffer)) != -1) {            // 将buffer写到PoolingByteArrayOutputStream中            bytes.write(buffer, 0, count);        }        // 4. 将所有数据返回        return bytes.toByteArray();    } finally {        try {            // Close the InputStream and release the resources by "consuming the content".            entity.consumeContent();        } catch (IOException e) {            // This can happen if there was an exception above that left the entity in            // an invalid state.            VolleyLog.v("Error occured when calling consumingContent");        }        // 5. 归还buffer到字节池        mPool.returnBuf(buffer);        bytes.close();    }}

执行步骤见代码注释。这里不对ByteArrayPool类和PoolingByteArrayOutputStream展开。

HttpStack

HttpStack是一个接口,仅负责将request发送出去:

public interface HttpStack {    public HttpResponse performRequest(Request<?> request, Map additionalHeaders)        throws IOException, AuthFailureError;}

从最开始的对Volley类的分析可知,SDK version > 9的情况下使用HurlStack(java.net.HttpURLConnection),否则使用HttpClientStack(org.apache.http.client.HttpClient)。

stack各自实现了performRequest()方法,在内部正式发起了http请求。具体的用法参考各自的api文档,这里不详细展开了。

Request

Request类主要是保存着该次请求的参数和该次请求当前的状态,本身不含有请求相关的行为:

public abstract class Request implements Comparable> {    ...    public interface Method {        int DEPRECATED_GET_OR_POST = -1;        int GET = 0;        int POST = 1;        int PUT = 2;        int DELETE = 3;        int HEAD = 4;        int OPTIONS = 5;        int TRACE = 6;        int PATCH = 7;    }    ...    private final int mMethod;    private final String mUrl;    private String mRedirectUrl;    private String mIdentifier;    private final int mDefaultTrafficStatsTag;    private Response.ErrorListener mErrorListener;    private Integer mSequence;    private RequestQueue mRequestQueue;    private boolean mShouldCache = true;    private boolean mCanceled = false;    private boolean mResponseDelivered = false;    private RetryPolicy mRetryPolicy;        ...}

下面再来分析一下request.parseNetworkResponse(networkResponse)这个方法。以StringRequest为例:

@Overrideprotected Response parseNetworkResponse(NetworkResponse response) {    String parsed;    try {        parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));    } catch (UnsupportedEncodingException e) {        parsed = new String(response.data);    }    return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));}

可以看到它只是简单地将data转换成string,然后返回一个success的response。

而JsonObjectRequest的实现如下:

@Overrideprotected Response parseNetworkResponse(NetworkResponse response) {    try {        String jsonString = new String(response.data,                HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET));        return Response.success(new JSONObject(jsonString),                HttpHeaderParser.parseCacheHeaders(response));    } catch (UnsupportedEncodingException e) {        return Response.error(new ParseError(e));    } catch (JSONException je) {        return Response.error(new ParseError(je));    }}

它现将data转换成string,然后再生成一个JSONObject返回。

总结

综上,Volley的大致框架如下所述:

  1. 一个RequestQueue中包含两个内部queue,分别是cache queue和network queue。还有一个cache dispatcher和n个network dispatcher,它们都继承成于Thread,分别负责执行缓存和网络请求。还有一个delivery,负责分发请求结果。

  2. cache dispatcher在独立的线程上运行。cache dispatcher循环等待、取出并执行cache queue中的request。把结果交给delivery。

  3. N个network dispatcher分别在独立的线程上运行。network dispatcher循环等待、取出并执行network queue中的request。把结果交给delivery和添加到cache中。

  4. delivery负责在主线程上将结果传给相应的listener回调。

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. Python list sort方法的具体使用
  3. python list.sort()根据多个关键字排序的方法实现
  4. Android(安卓)MediaPlayer 常用方法介绍
  5. Android(安卓)单元测试小总结
  6. Android中如何引入Lambda表达式
  7. android获取正在运行的进程
  8. android中HttpURLConnection调用getResponseCode()时崩溃 解决方
  9. Android(安卓)MapView 申请apiKey

随机推荐

  1. <转>android 中px,sp等的区别
  2. 重定向android log
  3. android多进程及AIDL简单使用
  4. android 中使用TextView实现分段显示不同
  5. android surfaceflinger研究
  6. 【Android volley】Android库Volley的使
  7. Android Q 电量使用图分析 show app usag
  8. 【startActivityForResult】Android Acti
  9. [android源码下载索引贴】微信+二维码那
  10. Android中OpenMax的适配层