Volley net

来源:互联网 发布:手机音频合成软件 编辑:程序博客网 时间:2024/04/30 05:19

如同上一篇学习的过程:

也从请求开始顺藤摸瓜:由于volley是不支持大文件操作的我们只看get和post请求;

get请求:

post请求:

<span style="white-space:pre"></span>private void postMethod() {JsonObjectRequest jsonRequest=new JsonObjectRequest(Method.POST, "url", null, new MyListener(), new MyVolleyErrorListener());mQueue.add(jsonRequest);}public class MyVolleyErrorListener implements com.ysheluo.volley.volley.Response.ErrorListener{@Overridepublic void onErrorResponse(VolleyError error) {}}public class MyListener implements  Listener<org.json.JSONObject>{@Overridepublic void onResponse(JSONObject response) {}}
一次post请求就已经完成十分的方便,追根溯源,我们先去看Volley.newRequestQueue(this);  到底做了什么,为什么仅仅是把一个request添加到里面就会去执行:

newRequestQueue有四个重载方法:最终调用的是:

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;    }
首先是在cachedir中创建了一个名为volley的缓存文件:  

File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

然后根据安卓版本进行了判别,当版本在9以上使用了HttpURLConnection而以下使用了HttpClient

 <span style="white-space:pre"></span>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);
默认情况下我们不指定缓存大小是会执行,默认大小是5M

queue = new RequestQueue(new DiskBasedCache(cacheDir), network);

这里进行了默认的配置:

  /** Number of network request dispatcher threads to start. */
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;

即volley默认初始线程池中维持的线程为4

然后进行queue.start()

    /**     * Starts the dispatchers in this queue.     */    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();        }    }
看代码最终得知遍历调用了
CacheDispatcher和NetworkDispatcher的start方法,二者均是thread的子类;这里先是创建了一个CacheDispatcher的实例,然后调用了它的start()方法,接着在一个for循环里去创建NetworkDispatcher的实例,并分别调用它们的start()方法。这里的CacheDispatcher和NetworkDispatcher都是继承自Thread的,而默认情况下for循环会执行四次,也就是说当调用了Volley.newRequestQueue(context)之后,就会有五个线程一直在后台运行,不断等待网络请求的到来, 其中 CacheDispatcher是缓存线程,也就是当访问在极短的时间内volley会调用本地缓存的数据直接返回,置于这个缓存有效的时间,还需要往下面看,看他是什么情况下将request标记为缓存有效,以及什么时候缓存过期的;NetworkDispatcher是网络请求线程。调用
mCacheDispatcher.start();也就是执行其run方法,我们看run方法里面是怎么进行操作的:

@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();        while (true) {            try {                // Get a request from the cache triage queue, blocking until                // at least one is available.                final Request<?> request = mCacheQueue.take();                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.                    mDelivery.postResponse(request, response, new Runnable() {                        @Override                        public void run() {                            try {                                mNetworkQueue.put(request);                            } catch (InterruptedException e) {                                // Not much we can do about this.                            }                        }                    });                }            } catch (InterruptedException e) {                // We may have been interrupted because it was time to quit.                if (mQuit) {                    return;                }                continue;            }        }    }
而我们看RequestQueue的add(Request<T> request)方法

  request.setRequestQueue(this);  synchronized (mCurrentRequests) {    mCurrentRequests.add(request);  }<span style="white-space:pre"></span>
mCurrentRequests是一个HashSet

接下来是:

  // If the request is uncacheable, skip the cache queue and go straight to the network.
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);
            return request;
   }
如果这个请求不允许缓存那么就直接添加到mNetworkQueue里面并返回request;
如果允许(默认情况下是true)就获取cachekey值

<span style="white-space:pre"></span>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);            }
检查存放requestqueue的mWaitingRequests是否包含该cache值,然后如果有的话就取出对应的含有该请求的列表,因为可能是多次请求的,所以volley建立一个linkedlist进行维持,当不存在时放一个key为cachekey,value值为null的,用来标识有这个缓存请求了。

那么volley是怎么设定缓存的作用范围呢?即缓存策略呢:就反过来查看NetworkDispatcher的run方法:

<span style="white-space:pre"></span>Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        while (true) {            long startTimeMs = SystemClock.elapsedRealtime();            Request<?> request;            try {                // Take a request from the queue.                request = mQueue.take();            } catch (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);
mNetwork是创建RequestQueue时的Network network = new BasicNetwork(stack);,真正指向的是子类BasicNetWork,追踪朔源,查看它的performRequest(request)方法:
其中核心是也就是真正去请求网络的方法: mHttpStack.performRequest(request, headers);

由于安卓6.0已经移除httpclient故这里仅查看HttpUrlClient,也就是主要关注 HurlStack类;查看其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);        int responseCode = connection.getResponseCode();        if (responseCode == -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;    }

这里volley请求大致流程就结束了。


















0 0
原创粉丝点击