Volley 解析

来源:互联网 发布:powerdvd源码输出 编辑:程序博客网 时间:2024/05/16 02:39

首先简单介绍下使用方法。
1 通过Volley 这个类 创建一个 RequestQueue

RequestQueue mRequestQueue = Volley.newRequestQueue(context);

2 创建一个Request
Request 分为StringRequest,ImageRequest,JsonArrayRequest,JsonObjectRequest,ImageLoader
其中ImageLoader继承自ImageRequest,也可以自定义Request。
拿StringRequest为例

StringRequest stringRequest = new StringRequest("http://www.baidu.com",                          new Response.Listener<String>() {                              @Override                              public void onResponse(String response) {                              }                          }, new Response.ErrorListener() {                              @Override                              public void onErrorResponse(VolleyError error) {                              }                          });  

3 将request放RequestQueue中

mRequestQueue.add(stringRequest);

下面研究一下源码,先从Volley的newRequestQueue入手,Volley有3个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;}

BasicNetwork 默认的网络请求实现类。
很简单,创建一个RequestQueue并启动它。看看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();    }}

一个RequestQueue维护一个CacheDispatcher和一组NetworkDispatcher,这个数组的size 等于 线程池大小。
CacheDispatcher 缓存分发器,NetworkDispatcher网络分发器,两者都继承自Thread。他们的run方法都是一个while循环,CacheDispatcher 不停地从mCacheQueue take() Request,而每一个networkDispatcher都从networkQueue 这一个queue中读取Request,由此可以看出Volley是一个高并发的框架。

那么就看看NetworkDispatcher都干什么吧,如下:

public void run() {        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        Request<?> request;        while (true) {            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 (request.isCanceled()) {                    request.finish("network-discard-cancelled");                    continue;                }                addTrafficStatsTag(request);                // 调用mNetwork去跟网络打交道                NetworkResponse networkResponse = mNetwork.performRequest(request);                request.addMarker("network-http-complete");                // 如果服务器返回一个未修改(304)的响应,并且这个请求已经发送过响应对象,不需要再继续,因为没改过                if (networkResponse.notModified && request.hasHadResponseDelivered()) {                    request.finish("not-modified");                    continue;                }                // 分析响应的数据,返回Response对象                Response<?> response = request.parseNetworkResponse(networkResponse);                request.addMarker("network-parse-complete");                // 根据request的shouldCache字段来判断是不是需要缓存,如果需要,则将其放到mCache中。                if (request.shouldCache() && response.cacheEntry != null) {                    mCache.put(request.getCacheKey(), response.cacheEntry);                    request.addMarker("network-cache-written");                }                // 调用 mDelivery将Response对象传回主线程进行UI的更新。                request.markDelivered();                mDelivery.postResponse(request, response);            } catch (VolleyError volleyError) {                parseAndDeliverNetworkError(request, volleyError);//有错误,也会调用到mDelivery,将错误信息传回到主线程,进行提示            } catch (Exception e) {                VolleyLog.e(e, "Unhandled exception %s", e.toString());                mDelivery.postError(request, new VolleyError(e));            }        }    }

网络线程(NetworkDispatcher)主要做了几件事情:
1)调用 mQueue的take()方法从队列中获取请求,如果没有请求,则一直阻塞在那里等待,直到队列中有新的请求到来。
2)判断请求有没有被取消,如果被取消,则重新获取请求。
3)调用Network对象将请求发送到网络中,并返回一个 NetworkResponse对象。
4)调用请求的pareseNetworkResonse方法,将NetworkResponse对象解析成相对应的Response对象。
5)判断请求是否需要缓存,如果需要缓存,则将其Response中cacheEntry对象放到缓存mCache中。
6)调用 mDelivery将Response对象传到主线程中进行UI更新。
另外有一个要注意的就是,在Volley中,默认是有4个网络线程同时在跑的,而对应的缓存线程,则只有一个。
从上面的代码中,可以看到,网络线程其实是调用 Network对象去实现跟网络进行沟通的,而在Volley中,默认的Network实现类,则是BasicNetwork类。

下面我们就看看它的performRequest方法:

public NetworkResponse performRequest(Request<?> request) throws VolleyError {        ...        while (true) {            HttpResponse httpResponse = null;            byte[] responseContents = null;            Map<String, String> responseHeaders = new HashMap<String, String>();            try {                // 添加头部信息                Map<String, String> headers = new HashMap<String, String>();                addCacheHeaders(headers, request.getCacheEntry());                httpResponse = mHttpStack.performRequest(request, headers);//调用HttpStack对象去网络中获取数据                StatusLine statusLine = httpResponse.getStatusLine();                int statusCode = statusLine.getStatusCode();                responseHeaders = convertHeaders(httpResponse.getAllHeaders());                // 从响应的状态行获取状态编码,如果是304(未修改),说明之前已经取过数据了,那么就直接利用缓存中的数据,构造一个NetworkResonse对象                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,                            request.getCacheEntry() == null ? null : request.getCacheEntry().data,                            responseHeaders, true);                }                // 有些响应是不带内容的,比如响应状态编码是204的话,添加一个空的byte作为内容,后面好统一处理。                if (httpResponse.getEntity() != null) {                  responseContents = entityToBytes(httpResponse.getEntity());                } else {                  // Add 0 byte response as a way of honestly representing a                  // no-content request.                  responseContents = new byte[0];                }                ...//忽略了一些log的处理。                return new NetworkResponse(statusCode, responseContents, responseHeaders, false);            } ...//这里忽略了一些异常处理            } catch (IOException e) {                ...                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));//这里会根据Volley的Retyr机制进行重新获取。                    } else {                        throw new ServerError(networkResponse);                    }                } else {                    throw new NetworkError(networkResponse);                }            }        }    }

BasicNetwork做的事情如下:
1)对于已经有缓存的请求,添加其头部信息,如下:

private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {    // If there's no cache entry, we're done.    if (entry == null) {        return;    }    if (entry.etag != null) {        headers.put("If-None-Match", entry.etag);    }    if (entry.serverDate > 0) {        Date refTime = new Date(entry.serverDate);        headers.put("If-Modified-Since", DateUtils.formatDate(refTime));    }    }

2)调用 HttpStack 对象去网络中获取数据,返回httpResonse 对象。
3)根据状态编码来返回不同的Response对象,如304(未修改)就返回缓存中的数据,如果不是,则根据响应中的数据,重新构造一个NetworkResponse对象。

4)BasicNetwork实现了重试的机制,如果第一次从网络获取失败,默认会重新再尝试一次,如果失败,则会将Error返回,默认的实现类是DefaultRetryPolicy类。

在Network中返回的NetworkResponse对象,会在NetworkDispatcher中由具体的Request(比如ImageRequest,JsonRequest)类来进行解析,再最后返回给UI线程。

1 0
原创粉丝点击