Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

6、volley 源码解析之工作流程综述

$
0
0

文章摘要
1、volley 中的工作线程
2、volley 工作步骤
3、RequestQueue初始化以及初始化逻辑


附:获取Volley源代码
Demos案例源码:https://github.com/HailouWang/DemosForApi

感悟:

Volley的源代码真的值得去读,其中包含了很多非常好的处理逻辑,例如:Volley对其工作流程的架构、线程缓存的处理、网络请求数据的解析以及处理、其中用到的设计模式等。

当我们明确了volley要解决的开发痛点后,volley提供了松耦合的架构实现,我们可以很方便的在其框架实现内,为其进行功能扩展。引用设计模式的一句话:一切为了松耦合的设计而努力。

简介:

volley有两个主要的民工,CacheDispatcher以及NetworkDispatcher,也是两个线程,管理并处理Request任务。

volley为了保证大批量的网络请求以及数据解析不会影响到主线程的用户交互,使用了很多线程以及线程封装技巧。包括这里的Cache。

在用户发起网络请求后,volley就将用户的请求,丢到了本文介绍的缓存进程,缓存线程如果没有能力处理,就丢给网络线程,并告诉它,老大需要数据结果,你赶紧去网络上去拿。老大只要结果,不要过程。

主线程很忙,ResponseDelivery负责传递消息,伴君如伴虎,为了防止打扰到主线程的工作,ResponseDelivery也可以有一个线程,在目前的源码里,ResponseDelivery充分利用Handler的MessageQueue优势,管理并小心的将结果传递给主线程。

1、volley 中,存在三类线程:

  • 1、主线程。将获取的数据刷新到UI,发送网络请求等。
  • 2、缓存进程(Cache Thread)。管理缓存数据,主线程的请求,优先从主线程中获取数据,其次将请求分发到网络中。
  • 3、网络线程(Network Thread)。用户可以制定网络线程的数量,默认是4个。定义了从网络获取数据的流程,但不包括网络同步逻辑。这样子的设计,可以更好的释放线程和网络解析逻辑之间的耦合。
for (int i = 0; i < DEFAULT_NETWORK_THREAD_POOL_SIZE; i++) {
    NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
      mCache, mDelivery);
    mDispatchers[i] = networkDispatcher;
    networkDispatcher.start();
}

2、volley 工作步骤

之前的Demos中发送一个简单的请求,无论是通过RequestQueue还是通过ImageLoader,大致的使用步骤是一样的,大体包括以下步骤:

  • 2.1、初始化RequestQueue或者ImageLoader。
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
  • 2.2、初始化Request
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        // Display the first 500 characters of the response string.
        mTextView.setText("Response is: "+ response.substring(0,500));
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mTextView.setText("That didn't work!");
    }
});
  • 2.3、 将Request 加入到RequestQueue。
// Add the request to the RequestQueue.
queue.add(stringRequest);

后两个步骤,是对RequestQueue的使用,所以,我们将重点放在第一部分,即:RequestQueue的创建流程。

3、RequestQueue初始化

RequestQueue会对Request进行管理,它的作用,更多的是作为一个工具类,通过add方法,将Request分发给Cache线程以及网络线程。

  • 3.1、首先通过newRequestQueue方法获得RequestQueue对象。
    public static RequestQueue newRequestQueue(Context context) {
        //1、初始化Network对象。Network的意义是通过performRequest方法解析Request,生成Response对象。
        HttpStack stack;
        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);
        //2、初始化RequestQueue,共计两个参数:第一个参数是Cache缓冲区,可选,即:可不缓冲。
        //第二个参数是network对象,也是关系解析网络数据的主要劳工。
        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        queue.start();

        return queue;
    }

Cache类图
- 3.2、RequestQueue的实例初始化,调用start后,线程会跑起来。

    /**
     * Creates the worker pool. Processing will not begin until {@link #start()} is called.
     *创建一个工作池,非start方法调用前,不会开始执行
     * @param cache A Cache to use for persisting responses to disk
     * 1、缓存者。将相应数据持久化到硬盘
     * @param network A Network interface for performing HTTP requests
     * 2、网络处理者。处理HTTP请求的Network 接口
     * @param threadPoolSize Number of network dispatcher threads to create
     * 3、网络请求分发者。默认4个分发线程池
     * @param delivery A ResponseDelivery interface for posting responses and errors
     * 4、响应传递者。运行在主线程,传递响应数据,以及错误日志信息,实现来自:Handler的封装
     */
    public RequestQueue(Cache cache, Network network, int threadPoolSize,
            ResponseDelivery delivery) {
        mCache = cache;
        mNetwork = network;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }

4、RequestQueue将Request抛给工作线程

RequestQueue通过add方法,将Request抛给工作线程,工作线程包含我们上面说的Cache线程、Network线程。

//1、将Request加入到mCurrentRequests,因为本工具类还需要管理Request,例如:cancel等。
// 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.
//2、包装Request。为其赋予SequenceNumber
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");

// If the request is uncacheable, skip the cache queue and go straight to the network.
//3、如果Request不需要缓存,则直接加入到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.
//4、如果请求(Request)不是在等待中(即:mWaitingRequests中),那么就先抛给缓冲线程(mCacheQueue)。
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<>();
        }
        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)在获得Request后,接着如何处理,请关注:volley 源码解析之缓存线程工作流程


关注我的技术公众号,查看更多优质技术文章推送

微信扫一扫下方二维码即可关注:

关注我的技术公众号,查看更多优质技术文章推送

作者:hailushijie 发表于2017/7/30 13:26:12 原文链接
阅读:31 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>