欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Volley源码解析

程序员文章站 2022-06-20 21:03:10
...

从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源码分析结束。

相关标签: 源码解析