Volley源码解析

Volley分为三个线程,主线程、缓存调度线程、网络调度线程。当要执行request时,需要先将request加入到缓存调度队列,如果发现有相应的缓存结果,则将该结果解析然后回调到主线程;当没有发现相应的缓存调度结果时,发送Http请求,解析响应,写入缓存,回调响应结果到主线程

RequestQueue queue= Volley.newRequestQueue(getApplicationContext());

此处是作为Volley的入口,即获得一个请求队列,此队列是通过Volley类获得的。去看看Volley里做了什么

RequestQueue newRequestQueue(Context context)
RequestQueue newRequestQueue(Context context, HttpStack stack)
RequestQueue newRequestQueue(Context context, int maxDiskCacheBytes)
RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes)

Volley共有四个构造函数,所有构造函数都会调用到第四个构造函数,即:

 public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
        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) {
                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);
        }
        else
        {
            // Disk cache size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
        }

        queue.start();

        return queue;
    }

构造函数里,首先回去获得缓存文件目录,紧接着根据不同的版本创建不同的HttpStack,再创建了Network和RequestQueue,最后将请求队列queue返回。其中queue即是我们需要获得的请求队列,RequestQueue构造时接收两个参数,一个是DiskBasedCache缓存响应结果,另一个是Network执行网络请求。不禁要问,在Volley的构造过程中,具体做了些什么?

public interface HttpStack {
    /**
     * Performs an HTTP request with the given parameters.
     *
     */
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
        throws IOException, AuthFailureError;

}

首先看的是HttpStack,HttpStack是一个接口,注释里写得很清楚,根据给予的参数执行Http请求

@Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        ......

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

       ......
        return response;
    }
@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);
    }

上面分别是HurlStack和HttpClientStack对接口HttpStack的实现。 当版本大于等于9时选择的基于HttpConnection的HurlStack,反之为基于HttpClient的HttpClientStack。两种实现都对请求做了处理,包括请求头部的处理

接下来是Network

public interface Network {
    /**
     * Performs the specified request.
     */
    public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}

Network也是一个接口,执行具体的请求

BasicNetwork(HttpStack httpStack)
BasicNetwork(HttpStack httpStack, ByteArrayPool pool)
NetworkResponse performRequest(Request<?> request)

BasicNetwork实现Network接口,且接收之前HttpStack ,并在performRequest里执行具体的请求

在以上的工作做好后,就可以创建RequestQueue

public class RequestQueue {
    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
    private final Map<String, Queue<Request<?>>> mWaitingRequests =
            new HashMap<String, Queue<Request<?>>>()
    PriorityBlockingQueue<Request<?>> mCacheQueue =
        new PriorityBlockingQueue<Request<?>>();
    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
        new PriorityBlockingQueue<Request<?>>();
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
    private final Network mNetwork;
    private final ResponseDelivery mDelivery;
    private NetworkDispatcher[] mDispatchers;
    private CacheDispatcher mCacheDispatcher;
}
public RequestQueue(Cache cache, Network network) {
        this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
    }
}

public abstract class Request implements Comparable

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

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

在start()里 , 会将所有的网络调度线程和缓存调度线程停止,见stop() . 然后分别开启新的网络调度线程和缓存调度线程。 那我们有必要看看两种调度线程是怎样运转的

首先是缓存调度进程

 public CacheDispatcher(
            BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
            Cache cache, ResponseDelivery delivery) {
        mCacheQueue = cacheQueue;
        mNetworkQueue = networkQueue;
        mCache = cache;
        mDelivery = delivery;
    }

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

                // Attempt to retrieve this item from cache.
                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 it is completely expired, just send it to the network.
                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());
            }
        }
    }

CacheDispatcher继承Thread,构造函数接收缓存队列,网络队列,缓存,响应发送
run方法比较长,耐心看

首先,会将线程切换到后台进程,然后初始化Cache即DiskBasedCache,配置好缓存相关工作。接着不断轮询从缓存队列读取Request,读取到Request后, 如果Request被取消,finish这个Request,进入下一个轮询;从缓存中读取Request的响应结果,如果读取不到,将Request加入到网络队列,如果读取到但过期了,将Request加入网络队列,关联到缓存。response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders)) 这里执行网络请求并且得到Response。 别忘了, request是一个借口,所在稍后会看到它的具体实现。

public interface ResponseDelivery {
    /**
     * Parses a response from the network or cache and delivers it.
     */
    public void postResponse(Request<?> request, Response<?> response);

    /**
     * Parses a response from the network or cache and delivers it. The provided
     * Runnable will be executed after delivery.
     */
    public void postResponse(Request<?> request, Response<?> response, Runnable runnable);

    /**
     * Posts an error for the given request.
     */
    public void postError(Request<?> request, VolleyError error);
}

在得到请求响应Response后,用ResponseDelivery将Response回调给主线程,同样得,ResponseDelivery也是一个接口

再来是网络调度NetworkDispatcher

public NetworkDispatcher(BlockingQueue<Request<?>> queue,
            Network network, Cache cache,
            ResponseDelivery delivery) {
        mQueue = queue;
        mNetwork = network;
        mCache = cache;
        mDelivery = delivery;
    }

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 {
                // Take a request from the queue.
                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);
            }
        }
    }

NetworkDispatcher一样继承Thread,构造函数接收网络队列,网络具体执行Network, 缓存,响应发送。
run()里也将线程切换为后台线程,不断从网络队列里读取Request,如果Request被取消,停止请求,通过Network执行网络请求,获得NetworkResponse,利用NetworkResponse得到需要的Response。 得到请求响应后,根据Request(在建立Request时候可以设置,默认为true)是否需要缓存结果,决定是否把响应结果加入到缓存。最后用mDelivery将响应结果发送出去。

看完了start(),还需要看add(),了解Request是如何加入进RequestQueue的

public <T> Request<T> add(Request<T> request) {
        // Tag the request as belonging to this queue and add it to the set of current requests.
        request.setRequestQueue(this);
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        // Process requests in the order they are added.
        request.setSequence(getSequenceNumber());
        request.addMarker("add-to-queue");

        // If the request is uncacheable, skip the cache queue and go straight to the network.
        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<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持有RequestQueue的引用,然后将Request加入到当前请求。如果Request的响应结果不需要缓存,直接加入到网络队列,结束这次add() 。 Request响应结果需要缓存,从等待请求mWaitingRequests查看Request是否存在,存在说明Request正在执行请求但还没有结果,将Request加入mWaitingRequests,不重复请求;如果不存在,将Request加入mWaitingRequests,加入缓存队列作为重复求情的依据。

最后来看看一个Request的实例,借助StringRequest

public class StringRequest extends Request<String> {
    private Listener<String> mListener;

    /**
     * Creates a new request with the given method.
     */
    public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    /**
     * Creates a new GET request.
     */
    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    @Override
    protected void onFinish() {
        super.onFinish();
        mListener = null;
    }

    @Override
    protected void deliverResponse(String response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }

    @Override
    protected Response<String> 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));
    }
}

parseNetworkResponse()将结果Parsed通过Response返回。 在之前的两个调度线程里,通过ResponseDelivery将结果发送出去,而ResponseDelivery是一个接口,在RequestQueue实例化的时候使用的是ExecutorDelivery,ExecutorDelivery实现了ResponseDelivery接口

public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
        request.markDelivered();
        request.addMarker("post-response");
        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    }

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");
                return;
            }

            // Deliver a normal response or error, depending.
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } 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();
            }
       }
    }

在ExecutorDelivery里postResponse()方法运行ResponseDeliveryRunnable,在这个Runnable里,如果Request已被取消,则不发送响应结果;如果响应结果成功调用mRequest.deliverResponse(mResponse.result),反之调用mRequest.deliverError(mResponse.error)。这里就会回调到StringRequest相应函数里,然后用StringRequest实例化时赋予的listener将结果回调到主线程。 到此,整个Volley流程结束

总结
1、在Volley实例RequestQueue, 将配置好的网路具体执行Network , 缓存DiskBasedCache 传给RequestQueue
2、RequestQueue 维护当前请求、等待请求、网络队列、缓存队列、缓存、请求响应传递、网络调度线程、缓存调度线程
3、在add新的Request时,根据不同的缓存需求对网络队列、缓存队列、等待请求做不同的操作。不缓存直接加入网络队列,缓存则加入缓存队列。 将缓存加入等待请求
4、缓存调度线程轮询时从缓存队列获取请求,再从缓存里获取此请求,命中则将请求响应结果发送出去,反之将请求加入到网络队列
5、网络调度线程轮询时从网络队列获取请求,获得请求响应结果后,如需缓存则缓存,然后将结果发送出去
6、调度线程通过具体的Request,调用parseNetworkResponse()方法获得response,然后通过ResponseDelivery接口将response发送出去,如在ExecutorDelivery里,ResponseDeliveryRunnable将结果回调到Request里,Request再回调用相应的listener将请求响应结果回调到主线程

此博客供个人笔记使用,如有错误之处,感谢指出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值