Volley源码解析

从newRequestQueue进行入手来进行一步步分析源码的流程
 public static RequestQueue newRequestQueue(Context context) {
        return newRequestQueue(context, null);
    }

 public static RequestQueue newRequestQueue(Context context, HttpStack stack)
{
    return newRequestQueue(context, stack, -1);
}

我们可以查看出来,它进行重载了两个方法来进行使用,最后的方法是下面这个

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
        //参数一:缓存到手机内置内存中
        //参数二:通过查看我们可以发现,这个文件夹的名字是volley
        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) {
        }

        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                //HttpUrlConnection中的stack
                stack = new HurlStack();
            } else {
                //HttpClient中的HttpClientStack
                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);
        }
        else
        {
            // Disk cache size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
        }

        queue.start();

        return queue;
    }

通过上面的代码我们可以看出来,它会判断当前的sdk的大小,如果当前的sdk>=9,它会调用HurlStack(),否则,它会调用HttpClientStack这个方法

1.HurlStack 与 HttpClientStack 区别

由此可见,在Android 2.2 中HttpClient拥有较少的bug,所以使用它比较合适,在Android 2.3以后HttpUrlConnection是最佳的选择。它的api简单,体积比较小,因此非常试用于Android项目。压缩和缓存机制可以有效的减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。

  1. HurlStack中的父类的源码进行分析

    /** 
     * An HTTP stack abstraction. 
     * 抽象的http栈 
     */  
    public interface HttpStack {  
        /** 
         * Performs an HTTP request with the given parameters. 
         * 根据参数,执行http请求 
         * <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise, 
         * and the Content-Type header is set to request.getPostBodyContentType().</p> 
         * 
         * @param request the request to perform 
         * @param additionalHeaders additional headers to be sent together with 
         *         {@link Request#getHeaders()} 
         * @return the HTTP response 
         */  
        public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)  
            throws IOException, AuthFailureError;  
    
    }  
    

该父类主要规定了,子类必须有一个根据request请求数据,并且返回HttpResponse类的方法

OK,接下来我们先看HurlStack,这个类使用的是HttpURLConnection作为连接方式,在sdk较高版本推荐使用(其实目前市场上2.3的系统已经很少见了)
我们直接看这个类的核心方法performRequest()

@Override  
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)  
        throws IOException, AuthFailureError {  
    String url = request.getUrl();  
    HashMap<String, String> map = new HashMap<String, String>();  
    map.putAll(request.getHeaders());  
    map.putAll(additionalHeaders);  
    if (mUrlRewriter != null) {  
        String rewritten = mUrlRewriter.rewriteUrl(url);  
        if (rewritten == null) {  
            throw new IOException("URL blocked by rewriter: " + url);  
        }  
        url = rewritten;  
    }  
    URL parsedUrl = new URL(url);  
    HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接  
    for (String headerName : map.keySet()) {//添加请求参数  
        connection.addRequestProperty(headerName, map.get(headerName));  
    }  
    setConnectionParametersForRequest(connection, request);//设置请求方式  
    // Initialize HttpResponse with data from the HttpURLConnection.  
    ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);//http协议  
    int responseCode = connection.getResponseCode();//获取响应状态  
    if (responseCode == -1) {//-1说明没有响应,抛出异常  
        // -1 is returned by getResponseCode() if the response code could not be retrieved.  
        // Signal to the caller that something was wrong with the connection.  
        throw new IOException("Could not retrieve response code from HttpUrlConnection.");  
    }  
    StatusLine responseStatus = new BasicStatusLine(protocolVersion,  
            connection.getResponseCode(), connection.getResponseMessage());//响应状态类  
    BasicHttpResponse response = new BasicHttpResponse(responseStatus);  
    response.setEntity(entityFromConnection(connection));//解析响应实体  
    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头  
        if (header.getKey() != null) {  
            Header h = new BasicHeader(header.getKey(), header.getValue().get(0));  
            response.addHeader(h);  
        }  
    }  
    return response;  
}  

整个方法分成几个步骤,首先是将请求参数,存储到map当中

HashMap<String, String> map = new HashMap<String, String>();  
       map.putAll(request.getHeaders());  
       map.putAll(additionalHeaders); 

然后是开启url连接

URL parsedUrl = new URL(url);  
HttpURLConnection connection = openConnection(parsedUrl, request);//开启连接  

来看openConnection()方法

/** 
 * Opens an {@link HttpURLConnection} with parameters. 
 * 开启网络连接 
 * @param url 
 * @return an open connection 
 * @throws IOException 
 */  
private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException {  
    HttpURLConnection connection = createConnection(url);  

    int timeoutMs = request.getTimeoutMs();  
    connection.setConnectTimeout(timeoutMs);  
    connection.setReadTimeout(timeoutMs);  
    connection.setUseCaches(false);  
    connection.setDoInput(true);  

    // use caller-provided custom SslSocketFactory, if any, for HTTPS  
    if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) {//https  
        ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory);  
    }  

    return connection;  
}  

 /** 
 * Create an {@link HttpURLConnection} for the specified {@code url}. 
 */  
protected HttpURLConnection createConnection(URL url) throws IOException {  
    return (HttpURLConnection) url.openConnection();  
}  

这个方法主要就是调用url.openConnevtion()从而返回一个HttpURLConnection对象,其中的一些超时设置,是由request本身提供的
另外还根据url是否带有https,为HttpURLConnection设置setSSLSocketFactory(mSslSocketFactory对象是在构造方法中传入的)
得到HttpURLConnection,就设置请求参数

for (String headerName : map.keySet()) {//添加请求参数  
            connection.addRequestProperty(headerName, map.get(headerName));  
        } 

然后是确定请求方式(GET,POST还是别的)

setConnectionParametersForRequest(connection, request);//设置请求方式  

setConnectionParametersForRequest方法:

@SuppressWarnings("deprecation")  
    /** 
     * 设置请求方式 
     * @param connection 
     * @param request 
     * @throws IOException 
     * @throws AuthFailureError 
     */  
    /* package */   
    static void setConnectionParametersForRequest(HttpURLConnection connection,  
            Request<?> request) throws IOException, AuthFailureError {  
        switch (request.getMethod()) {  
            case Method.DEPRECATED_GET_OR_POST:  
                // This is the deprecated way that needs to be handled for backwards compatibility.  
                // If the request's post body is null, then the assumption is that the request is  
                // GET.  Otherwise, it is assumed that the request is a POST.  
                byte[] postBody = request.getPostBody();  
                if (postBody != null) {  
                    // Prepare output. There is no need to set Content-Length explicitly,  
                    // since this is handled by HttpURLConnection using the size of the prepared  
                    // output stream.  
                    connection.setDoOutput(true);  
                    connection.setRequestMethod("POST");  
                    connection.addRequestProperty(HEADER_CONTENT_TYPE,  
                            request.getPostBodyContentType());  
                    DataOutputStream out = new DataOutputStream(connection.getOutputStream());  
                    out.write(postBody);  
                    out.close();  
                }  
                break;  
            case Method.GET:  
                // Not necessary to set the request method because connection defaults to GET but  
                // being explicit here.  
                connection.setRequestMethod("GET");  
                break;  
            case Method.DELETE:  
                connection.setRequestMethod("DELETE");  
                break;  
            case Method.POST:  
                connection.setRequestMethod("POST");  
                addBodyIfExists(connection, request);  
                break;  
            case Method.PUT:  
                connection.setRequestMethod("PUT");  
                addBodyIfExists(connection, request);  
                break;  
            case Method.HEAD:  
                connection.setRequestMethod("HEAD");  
                break;  
            case Method.OPTIONS:  
                connection.setRequestMethod("OPTIONS");  
                break;  
            case Method.TRACE:  
                connection.setRequestMethod("TRACE");  
                break;  
            case Method.PATCH:  
                connection.setRequestMethod("PATCH");  
                addBodyIfExists(connection, request);  
                break;  
            default:  
                throw new IllegalStateException("Unknown method type.");  
        }  
    }  

最后获取响应,将响应头信息包装成StatusLine对象,再包装成BasicHttpResponse对象

StatusLine responseStatus = new BasicStatusLine(protocolVersion,  
                connection.getResponseCode(), connection.getResponseMessage());//响应状态类  
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);  

然后为BasicHttpResponse加入响应内容

response.setEntity(entityFromConnection(connection));//解析响应实体  

entityFromConnection(HttpURLConnection connection)方法:

/** 
     * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}. 
     * <br>解析出响应实体 
     * @param connection 
     * @return an HttpEntity populated with data from <code>connection</code>. 
     */  
    private static HttpEntity entityFromConnection(HttpURLConnection connection) {  
        BasicHttpEntity entity = new BasicHttpEntity();  
        InputStream inputStream;  
        try {  
            inputStream = connection.getInputStream();  
        } catch (IOException ioe) {  
            inputStream = connection.getErrorStream();  
        }  
        entity.setContent(inputStream);  
        entity.setContentLength(connection.getContentLength());  
        entity.setContentEncoding(connection.getContentEncoding());  
        entity.setContentType(connection.getContentType());  
        return entity;  
    }  

最后,加入响应头部内容

 for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {//添加响应头  
            if (header.getKey() != null) {  
                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));  
                response.addHeader(h);  
            }  
        }  

OK,这样就返回了一个具有完整信息的HttpResponse对象。整个过程比较简单,是常规的网络请求内容。

2.HttpClientStack的实现,直接来看performRequest()方法

@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();  
    // TODO: Reevaluate this connection timeout based on more wide-scale  
    // data collection and possibly different for wifi vs. 3G.  
    HttpConnectionParams.setConnectionTimeout(httpParams, 5000);  
    HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);  
    return mClient.execute(httpRequest);  
}  

请求步骤,首先是根据请求方式,构造HttpUriRequest对象,并且设置请求参数

HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); 

createHttpRequest()方法:

/** 
 * Creates the appropriate subclass of HttpUriRequest for passed in request. 
 * 根据请求方式返回对应HttpUriRequest的子类 
 */  
@SuppressWarnings("deprecation")  
/* protected */   
static HttpUriRequest createHttpRequest(Request<?> request,  
        Map<String, String> additionalHeaders) throws AuthFailureError {  
    switch (request.getMethod()) {  
        case Method.DEPRECATED_GET_OR_POST: {  
            // This is the deprecated way that needs to be handled for backwards compatibility.  
            // If the request's post body is null, then the assumption is that the request is  
            // GET.  Otherwise, it is assumed that the request is a POST.  
            byte[] postBody = request.getPostBody();  
            if (postBody != null) {  
                HttpPost postRequest = new HttpPost(request.getUrl());  
                postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());  
                HttpEntity entity;  
                entity = new ByteArrayEntity(postBody);  
                postRequest.setEntity(entity);  
                return postRequest;  
            } else {  
                return new HttpGet(request.getUrl());  
            }  
        }  
        case Method.GET:  
            return new HttpGet(request.getUrl());  
        case Method.DELETE:  
            return new HttpDelete(request.getUrl());  
        case Method.POST: {  
            HttpPost postRequest = new HttpPost(request.getUrl());  
            postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
            setEntityIfNonEmptyBody(postRequest, request);//设置请求参数  
            return postRequest;  
        }  
        case Method.PUT: {  
            HttpPut putRequest = new HttpPut(request.getUrl());  
            putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
            setEntityIfNonEmptyBody(putRequest, request);  
            return putRequest;  
        }  
        case Method.HEAD:  
            return new HttpHead(request.getUrl());  
        case Method.OPTIONS:  
            return new HttpOptions(request.getUrl());  
        case Method.TRACE:  
            return new HttpTrace(request.getUrl());  
        case Method.PATCH: {  
            HttpPatch patchRequest = new HttpPatch(request.getUrl());  
            patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
            setEntityIfNonEmptyBody(patchRequest, request);  
            return patchRequest;  
        }  
        default:  
            throw new IllegalStateException("Unknown request method.");  
    }  
}  

从createHttpRequest()方法可以看出,在HttpClient中,只要根据请求方式,new一个HttpGet/HttpPost/….对象就可以了(而urlstack这一步是真的connnection而言的)
接着是为HttpUriRequest对象设置请求头部

   addHeaders(httpRequest, additionalHeaders);//添加缓存头  
   addHeaders(httpRequest, request.getHeaders());//添加请求头  

addHeaders方法:

/** 
 * 添加响应头 
 * @param httpRequest 
 * @param headers 
 */  
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {  
    for (String key : headers.keySet()) {  
        httpRequest.setHeader(key, headers.get(key));  
    }  
}  

最后,将HttpUriRequest对象交给httpClient执行

return mClient.execute(httpRequest);  

3.HurlStack与HttpClientStack区别进行总结

OK,HttpClientStack比我们想象的还要简单,起码比HurlStack简单,这是当然的,因为使用httpClient方式,其本质就是对urlConnection的封装,然而这个封装并不是很完美,所以造成了版本之间的差异。

2. new RequestQueue(new DiskBasedCache(cacheDir), network)这里面的源码进行分析

我们点击跳转到这个构造方法中

//参数一:缓存 参数二:联网工作的状态
public RequestQueue(Cache cache, Network network) {
    this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}

当点击里面的那个this方法时候会跳转到如下构造函数中
  public RequestQueue(Cache cache, Network network, int threadPoolSize) {
    this(cache, network, threadPoolSize,
            new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}

通过分析我们可以发现,最后是将网络请求响应的数据发送到主线程进行操作的

3.queue.start(); 这个里面的方法中进行分析
   public void start() {
        //确保当前正在运行的调度程序已经停止
        stop();  
        //参数一:实例化缓存分流队列
        //参数二:实际化到达网络的请求队列
        //参数三:用于检索和存储响应的高速缓存接口
        //参数四:响应传递机制
        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();
        }
    }

CacheDispatcher是缓存调度线程,在调用start()方法。在循环中调用了NetworkDispatcher网络调度线程。默认情况下网络调度线程是4,缓存调度线程是一个,一共5个线程在后台运行并等待请求的到来。同时进行添加到请求到队列里面来。

接下来我们一起来看一下add()方法的源码进行分析
 public <T> Request<T> add(Request<T> request) {

        // 将此请求与指定的队列进行关联,当这个请求队列被通知
        request.setRequestQueue(this);
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        // 按照添加的顺序处理请求
        request.setSequence(getSequenceNumber());
        request.addMarker("add-to-queue");

        // 如果不能缓存,将请求添加到网络请求队列中
        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();
            //如果此前有相同的请求且还没有返回结果,就将次请求加入mWaitingRequests队列
            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 {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);
                mCacheQueue.add(request);
            }
            return request;
        }
    }

代码分析:request.shouldCache()判断是否可以进行缓存的,默认是可以缓存的。如果不能缓存,则将请求添加到网络请求队列里面。如果能缓存,则判断之前是否有执行相同的请求且没有返回结果的,如果有的话将此请求加入到mWaitingRequests队列中,不再进行重复的请求,没有的话就请求加入到缓存的队列mCacheQueue.RequestQueue的add方法并没有请求网络或者对缓存的操作,当将请求添加到网络请求的队列或者缓存队列时,在后台的网络调度线程和缓存调度线程轮询各自的请求队列,若发现有请求任务则开始执行。

我们来看一下缓存调度线程CacheDispatcher
@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;
        try {
            // 获取缓存队列中的一个请求
            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 (request.isCanceled()) {
                request.finish("cache-discard-canceled");
                continue;
            }

            // 查看是否有缓存的响应
            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;
            }

            // 判断缓存的响应是否过期
            if (entry.isExpired()) {
                request.addMarker("cache-hit-expired");
                request.setCacheEntry(entry);
                mNetworkQueue.put(request);
                continue;
            }

            // We have a cache hit; parse its data for delivery back to the request.
            request.addMarker("cache-hit");
            //对数据的解析并回调给主线程
            Response<?> response = request.parseNetworkResponse(
                    new NetworkResponse(entry.data, entry.responseHeaders));
            request.addMarker("cache-hit-parsed");

            if (!entry.refreshNeeded()) {
                // Completely unexpired cache hit. Just deliver the response.
                mDelivery.postResponse(request, response);
            } else {
                // Soft-expired cache hit. We can deliver the cached response,
                // but we need to also send the request to the network for
                // refreshing.
                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());
        }
    }
}

分析:首先从缓存队列取出请求,判断请求是否取消,如果请求没有被取消则判断是否有缓存的响应,如果有缓存的响应。如果有缓存的响应并且没有过期,则对缓存响应进行解析并回调给主线程:如果没有缓存的响应,则将请求添加到网络调度线程

网络调度线程NetworkDispatcher
@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 {
            // 从队列中取出请求
            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);

            // Perform the 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()) {
                request.finish("not-modified");
                continue;
            }

            // Parse the response here on the worker thread.
            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) {
                mCache.put(request.getCacheKey(), response.cacheEntry);
                request.addMarker("network-cache-written");
            }

            // Post the response back.
            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);
        }
    }
}

这个网络调度线程和缓存调度线程处理的逻辑几乎相同,在这里,不做过多的介绍了,mNetwork.performRequest(request);我们可以观察到这个里面是个接口,实现类是BasicNetwork,我们来接着往下进行分析

1.Network接口类代码如下
public interface Network {
    /**
     * Performs the specified request.执行这个请求
     * @param request Request to process//待处理的请求
     * @return A {@link NetworkResponse} with data and caching metadata; will never be null
     * 返回一个请求结果,不会为空
     * @throws VolleyError on errors
     */
    public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
2.BasicNetwork中的performRequest里面的请求进行分析
 /**
 * @title performRequest执行各种Request请求并以NetworkResponse的形式返回结果
 * @param Request
 * @return NetworkResponse
 * @throws VolleyError
 * 定义:{@link Network#performRequest(Request)}
 * 被调:{@link NetworkDispatcher#run()}
 * 
 */
@Override//NetworkDispatcher的run()方法中调用
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();//开始请求时间
    while (true) {
        HttpResponse httpResponse = null;//apache的请求结果
        byte[] responseContents = null;//请求的内容
        Map<String, String> responseHeaders = new HashMap<String, String>();//响应结果头部信息
        try {
            // Gather headers.
            Map<String, String> headers = new HashMap<String, String>();//保存缓存数据
            addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据
            httpResponse = mHttpStack.performRequest(request, headers);//去调用mHttpStack的实现方法执行请求
            StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线
            int statusCode = statusLine.getStatusCode();//获取状态码

            responseHeaders = convertHeaders(httpResponse.getAllHeaders());
            // Handle cache validation.//处理缓存验证
            if (statusCode == HttpStatus.SC_NOT_MODIFIED) {//返回缓存数据
                return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
                        request.getCacheEntry().data, responseHeaders, true);
            }

            //把HttpEntity转化为byte[]数据
            responseContents = entityToBytes(httpResponse.getEntity());
            // if the request is slow, log it.//如果请求很慢,就打印出来看一下
            long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
            logSlowRequests(requestLifetime, request, responseContents, statusLine);//打印

            //连接正常但是返回无内容,抛出IO异常
            if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) {
                throw new IOException();
            }
            return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
        } catch (SocketTimeoutException e) {//读取超时,重试
            attemptRetryOnException("socket", request, new TimeoutError());
        } catch (ConnectTimeoutException e) {//连接超时,重试
            attemptRetryOnException("connection", request, new TimeoutError());
        } catch (MalformedURLException e) {//Bad URL
            throw new RuntimeException("Bad URL " + request.getUrl(), e);
        } catch (IOException e) {//IO异常
            int statusCode = 0;
            NetworkResponse networkResponse = null;
            if (httpResponse != null) {
                statusCode = httpResponse.getStatusLine().getStatusCode();
            } else {//如果没有返回httpResponse,就说明没连接
                throw new NoConnectionError(e);
            }
            VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
            if (responseContents != null) {//返回数据不为空
                networkResponse = new NetworkResponse(statusCode, responseContents,
                        responseHeaders, false);//创建响应体
                if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                        statusCode == HttpStatus.SC_FORBIDDEN) {//认证失败异常,重试
                    attemptRetryOnException("auth",
                            request, new AuthFailureError(networkResponse));
                } else {//服务器异常
                    // TODO: Only throw ServerError for 5xx status codes.
                    throw new ServerError(networkResponse);//只有状态码为5XX才抛出服务器异常
                }
            } else {//网络异常
                throw new NetworkError(networkResponse);
            }
        }
    }
}

代码解析:

1.先是通过mHttpStack把请求执行并且获取它的响应结果,根据HttpStatus做出各种判断。
2.然后再把httpResponse的Entity转化为ByteArray,并处理各种发生的异常。
3.最后的过程是这样的:通过Volley创建一个RequestQueue请求队列,当这个队列开始运作的时候会启动NetworkDispatcher这个工作线程,而BasicNetwork的performRequest()的方法就在NetworkDispatcher线程run()方法中调用,然后通过mHttpStack的performRequest()方法获取一个networkResponse,在NetworkDispatcher线程把这个networkResponse转化为期望的数据类型,比如Response<String>,Response<Json>,Response<Bitmap>。
3. mDelivery.postResponse(request, response);
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
    request.markDelivered();
    request.addMarker("post-response");
    mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
4.ResponseDeliveryRunnable我们来看一下这里面都做了什么处理的
/**
 * 在主线程进行返回一个网络响应的交付线程
 */
@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 (mRequest.isCanceled()) {
            mRequest.finish("canceled-at-delivery");
            return;
        }

        // 如果响应错误就可以调用错误的方法传入错误信息
        if (mResponse.isSuccess()) {
            mRequest.deliverResponse(mResponse.result);
        } else {
            mRequest.deliverError(mResponse.error);
        }

        // 如果这是一个中间响应,添加一个标记,否则我们就完成了。
        //请求可以完成
        if (mResponse.intermediate) {
            mRequest.addMarker("intermediate-response");
        } else {
            mRequest.finish("done");
        }

        // 如果提供了交付,我们进行请求它
        if (mRunnable != null) {
            mRunnable.run();
        }
   }
}

Volley源码分析结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值