volley框架源码解析

之前用过一次volley框架,觉得十分好用,在与服务器交互时十分方便,尤其在图像异步加载,传递json数据,缓存等,其在网络通信方面表现的极为出色,适合数据量不大,但请求频繁的应用,如加载图片。
volley使用一般步骤为:
1.通过volley的静态方法newRequestQueue()创建RequestQueue请求队列
2.创建request对象,volley官方提供了几种已经定义好的request类型。
一是:StringRequest用于请求String数据,服务器会返回String类型数据.
二是:JsonRequest是抽象类,他有两个子类:JsonObjectRequest和JsonArrayRequest。前者请求json数据,后者请求json数组.
三是:ImageRequest用于加载网络图片。
当然由于volley框架可扩展性好,你也可以自定义request来实现你的需求.
3.利用requestQueue的add()方法将request加入requestQueue队列中.

以上是volley框架使用过程,接下来我们好好看看volley框架的源码.
先看下官方给的volley框架工作流程图.
这里写图片描述

我们直接从字面意思上来理解,第一步把request添加到cachequeue缓存队列中,然后通过CacheDispatcher来取出request来处理,然后看缓存结果是否有效,有效则直接读取结果并解析,然后分发回主线程处理。否则,将通过NetworkDispatcher来分发,然后将网络返回结果进行解析,再返回到主线程处理。

接下来我们来逐步分析代码,首先通过volley.newRequestQueue()方法创建RequestQueue对象。

public class Volley {
    private static final String DEFAULT_CACHE_DIR = "volley";

    public static RequestQueue newRequestQueue(Context context) {
        return newRequestQueue(context, null);
    }

    private static RequestQueue newRequestQueue(Context context, HttpStack stack) {
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

        // Only use HttpURLConnection
        if (stack == null) {
            stack = new HurlStack();
        }

        Network network = new BasicNetwork(stack);

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

        return queue;
    }
}

我们从代码可以看出最后实现的就是RequestQueue newRequestQueue(Context context, HttpStack stack) 这个方法,而stack开始是空的,然后创建了一个新的HurlStack()对象,开始还创建了一个文件作为缓存,接下来又新建了一个Network的实现类BasicNetwork对象,然后调用RequestQueue的构造方法创建了RequestQueue对象,它的两个实参就是之前的创建的对象cacheDir和network。然后调用RequestQueue的start方法,来开启缓存队列和网络请求队列.最后返回requestQueue对象。
接下来来分析RequestQueue类代码。

public void start() {
        // 关闭所有正在运行的缓存线程和网络请求线程.
        stop();
        // 开启缓存线程.
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();     //CacheDispatcher类继承Thread,这里调用的是父类的start.

        // 默认开启DEFAULT_NETWORK_THREAD_POOL_SIZE(4)个线程来执行request网络请求.
        for (int i = 0; i < mDispatchers.length; i ++) {                      //默认的为4
            // 将NetworkDispatcher线程与mNetworkQueue这个队列进行绑定.
            // NetworkDispatcher会使用生产者-消费者模型从mNetworkQueue获取request请求,并执行.
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

上面就是在Volley里面调用的RequestQueue的start方法,在这里面最主要是开启缓存线程和网络请求线程,在这里mDispatchers.length默认是4,所以在执行完start后会有5个线程,1个缓存线程和4个网络请求线程,为什么会有1个缓存线程和4个网络请求线程呢?因为却大多数请求都会经过网络请求线程进行消费。然后在逐步来看mCacheDispatcher对象,它是CacheDispatcher的一个实例,然后调用CacheDispatcher.start方法。

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

    /** 通过标记位机制强行停止CacheDispatcher线程. */
    public void quit() {
        mQuit = true;
        interrupt();
    }

    @Override
    public void run() {
        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        // 初始化DiskBasedCache缓存类.
        mCache.initialize();  

        while (true) {
            try {
                // 从缓存队列中获取request请求.(缓存队列实现了生产者-消费者队列模型)
                final Request<?> request = mCacheQueue.take();

                // 判断请求是否被取消
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");       //结束当前请求,并直接开始下次循环
                    continue;
                }

                // 从缓存系统中获取request请求结果Cache.Entry.
                Cache.Entry entry = mCache.get(request.getCacheKey());      //Cache是缓存内存的接口,里面的内部类Entry才是真正HTTP请求缓存实体类
                if (entry == null) {
                    // 如果缓存系统中没有该缓存请求,则将request加入到网络请求队列中.
                    // 由于NetworkQueue跟NetworkDispatcher线程关联,并且也是生产者-消费者队列,
                    // 所以这里添加request请求就相当于将request执行网络请求.
                    mNetworkQueue.put(request);
                    continue;
                }

                // 判断缓存结果是否过期.
                if (entry.isExpired()) {
                    request.setCacheEntry(entry);
                    // 过期的缓存需要重新执行request请求.
                    mNetworkQueue.put(request);
                    continue;
                }

                // We have a cache hit; parse its data for delivery back to the request.
                Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data,              //NetworkResponse网络请求结果抽象类
                        entry.responseHeaders));    //直接解析缓存里面的请求结果

                // 判断Request请求结果是否新鲜?
                if (!entry.refreshNeeded()) {
                    // 请求结果新鲜,则直接将请求结果分发,进行异步回调用户接口.
                    mDelivery.postResponse(request, response);             //没有找到mDelivery的实现类,postResponse()具体实现逻辑未知.
                } else {
                    // 请求结果不新鲜,但是同样还是将缓存结果返回给用户,并且同时执行网络请求,刷新Request网络结果缓存.
                    request.setCacheEntry(entry);

                    response.intermediate = true;

                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(request);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                if (mQuit) {
                    return;
                }
            }
        }
    } 

从上面代码可以看出CacheDispatcher继承Thread,是一个线程,在RequestQueue里面启动CacheDispatcher线程。接下来我们来看run方法里面。在这里面while(true)表明该线程启动后一直处理。首先从缓存队列中取出request,然后通过request.getCacheKey()来获取缓存结果,若缓存结果为空则直接把请求加入网络请求队列,然后continue。若结果不为空则判断缓存结果是否过期,若过期还是加入网络请求队列,否则就直接从缓存中获取结果,将调用request.parseNetworkResponse将结果进行解析,然后判断请求结果是否新鲜,若新鲜则直接调用ResponseDelivery.postResponse方法将解析结果进行分发到主线程,否则再分发结果后,重新发起网络请求,刷新Request网络结果缓存.。
这就是我们完全走缓存路线的全部流程代码.
接下来来分析走网络请求队列部分。


    @Override
    public void run() {
        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        while (true) {
            long startTimeMs = SystemClock.elapsedRealtime();
            Request<?> request;
            try {
                // 使用BlockingQueue实现了生产者-消费者模型.
                // 消费者是该调度线程.
                // 生产者是request网络请求.
                request = mQueue.take();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }

            try {
                if (request.isCanceled()) {
                    continue;
                }

                addTrafficStatsTag(request);

                // 真正执行网络请求的地方.
                NetworkResponse networkResponse = mNetwork.performRequest(request);    //这里是调用Network接口的实现类BasicNetwork的performRequest(request),经过分析最终是调用调用HurlStack的performRequest方法执行网络请求

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

                // 在当前线程中解析网络结果.
                // 不同的Request实现的parseNetworkResponse是不同的(例如StringRequest和JsonRequest).
                Response<?> response = request.parseNetworkResponse(networkResponse);   //调用具体Request的parseNetworkResponse()方法解析网络结果.

                //
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                }   //如果这个请求可以缓存,且response中的request缓存不为空,则把response中的request缓存加入缓存结果mCache。

                // 将网络请求结果进行传递.
                // ResponseDelivery调用顺序如下:
                // ResponseDelivery.postResponse==>ResponseDeliveryRunnable[Runnable]->run
                // ==>Request->deliverResponse==>用户设置的Listener回调接口
                request.markDelivered();   //标记已经返回结果
                mDelivery.postResponse(request, response);   //调用request的deliverResponse()将结果传递给listener回调接口
            } catch (VolleyError volleyError) {
                volleyError.printStackTrace();
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                parseAndDeliverNetworkError(request, volleyError);
            } catch (Exception e) {
                VolleyError volleyError = new VolleyError(e);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                mDelivery.postError(request, volleyError);
            }
        }
    }

同上,NetworkDispatcher也是一个线程,我主要来看它的run方法。同样使用生产者和消费者模式,调用 NetworkResponse networkResponse = mNetwork.performRequest(request)来处理请求,也就是调用BasicNetwork的performRequest方法来处理,等下我们再来看Network的实现类BasicNetwork.继续往下看,判断返回结果是否为304状态且已经返回过结果,如果是则关闭request,continue.反之,解析结果。如果该request可以缓存且返回结果不为空,则在缓存中存储结果(在这里通过
mCache.put(request.getCacheKey(), response.cacheEntry)来储存,这跟之前我们分析缓存处理中从缓存中取结果所用方法相对应mCache.get(request.getCacheKey()))。然后设置该request的标记位markDelivered为true,表明已经返回过结果。
最后调用ResponseDelivery的postResponse方法分发结果。(这里最后是调用ResponseDelivery的实现类ExecutorDelivery的重写方法postResponse来处理,在这里面在返回成功后会调用具体request里面的重写方法deliverResponse()方法。)
最后我们再来看看之前BasicNetwork类。

 @Override
    public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        // 记录请求开始时间,便于进行超时重试
        long requestStart = SystemClock.elapsedRealtime();
        while (true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map<String, String> responseHeaders = Collections.emptyMap();
            try {
                // 构造Cache的HTTP headers,主要是添加If-None-Match和If-Modified-Since两个字段
                // 当客户端发送的是一个条件验证请求时,服务器可能返回304状态码.
                // If-Modified-Since:代表服务器上次修改是的日期值.
                // If-None-Match:服务器上次返回的ETag响应头的值.
                Map<String, String> headers = new HashMap<String, String>();
                addCacheHeaders(headers, request.getCacheEntry());

                // 调用HurlStack的performRequest方法执行网络请求, 并将请求结果存入httpResponse变量中
                httpResponse = mHttpStack.performRequest(request, headers);

                StatusLine statusLine = httpResponse.getStatusLine();      //获取返回结果的状态
                int statusCode = statusLine.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());

                // 当服务端返回304状态码时,直接将Volley缓存中结果返回
                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
                    Cache.Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
                                responseHeaders, true,
                                SystemClock.elapsedRealtime() - requestStart);
                    }

                    // A HTTP 304 response dose not have all header filed. We
                    // have to use the header fields from the cache entry plus
                    // the new ones from the response.
                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
                            entry.responseHeaders, true,
                            SystemClock.elapsedRealtime() - requestStart);
                }

                // Some responses such as 204s do not have content. We mush check
                if (httpResponse.getEntity() != null) {
                    responseContents = entityToBytes(httpResponse.getEntity());
                } else {
                    responseContents = new byte[0];
                }

                if (statusCode < 200 || statusCode > 299) {
                    throw new IOException();
                }

                return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
                        SystemClock.elapsedRealtime() - requestStart);
            } catch (SocketTimeoutException e) {
                // 捕获各种异常,进行重试操作.
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException E) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException e) {
                throw new RuntimeException("Bad URL " + request.getUrl(), e);
            } catch (IOException e) {
                int statusCode;
                if (httpResponse != null) {
                    statusCode = httpResponse.getStatusLine().getStatusCode();
                } else {
                    throw new NoConnctionError(e);
                }
                NetworkResponse networkResponse;
                if (responseContents != null) {
                    networkResponse = new NetworkResponse(statusCode, responseContents,
                            responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                    if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
                            statusCode == HttpStatus.SC_FORBIDDEN) {
                        attemptRetryOnException("auth",
                                request, new AuthFailureError(networkResponse));
                    } else if (statusCode >= 400 && statusCode <= 499) {
                        throw new ClientError(networkResponse);
                    } else if (statusCode >= 500 && statusCode <= 599) {
                        if (request.shouldRetryServerErrors()) {
                            attemptRetryOnException("server",
                                    request, new ServerError(networkResponse));
                        } else {
                            throw new ServerError(networkResponse);
                        }
                    } else {
                        // 3xx?
                        throw new ServerError(networkResponse);
                    }
                } else {
                    attemptRetryOnException("network", request, new NetworkError());
                }
            }
        }
    }

这里面最主要的方法就是performRequest()方法,在之前处理request时其实就是调用这个方法执行。
先看这句httpResponse = mHttpStack.performRequest(request, headers);它是调用HttpStack的performRequest方法来处理,所以最终的处理落在了HttpStack里面,而我们在这里面传进的是newRequestQueue方法中传入的HurlStack类。也就是通过HttpURLConnection来处理请求,接下来判断返回结果状态码是否为304,若是则直接返回缓存中的结果。反之返回将返回流数据转换成字节数组,作为返回的NetworkResponse的数据。至此网络处理请求也说完了。
接下来我们去看ExecutorDelivery源码

 @SuppressWarnings("unchecked")
    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;
        }

        @Override
        public void run() {
            // 如果request被取消,则不回调用户设置的Listener接口
            if (mRequest.isCanceled()) {
                mRequest.finish("canceled-at-delivery");
                return;
            }

            // 通过response状态标志,来判断是回调用户设置的Listener接口还是ErrorListener接口
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }

            if (mResponse.intermediate) {
                mRequest.addMarker("intermediate-response");
            } else {
                // 通知RequestQueue终止该Request请求
                mRequest.finish("done");
            }

            if (mRunnable != null) {
                mRunnable.run();
            }
        }
    }

在这里我们主要就看一段

if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }

这就是调用request中重写的方法deliverResponse和deliverError方法,将结果返回到主线程listener的onResponse()方法处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值