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

7、volley 源码解析之缓存线程工作流程

$
0
0

文章摘要
1、volley 缓存线程运行流程
2、volley 实现分解步骤


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

简介:

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

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

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

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

那么,本文就来介绍下缓存线程的工作原理:

一、CacheDispatcher线程

  • 1、Volley中有三个线程,CacheDispatcher是其中的缓存线程。

  • 2、CacheDispatcher缓冲线程的目的是在缓冲池中,执行分流,将Request请求分发出去。
    线程循环运行,线程原料来自mCacheQueue,在主线程可通过RequestQueue.add方法将请求加入mCacheQueue。

  • 3、可以将工作流程简单归纳为以下几步:

    • 1、线程循环运行,线程原料来自mCacheQueue。
    • 2、优先从缓冲区获得数据,如果缓存区中存在数据,则直接返回数据给主线程。
    • 3、如果缓存区【没有命中数据】或者【缓存数据过期】,则将请求(Request)分发给NetworkDispatcher(网络线程),网络线程会重新同步数据。

附:流程图

  • Volley Cache Thread流程图.png

二、实现分析

1、线程循环运行,获得Request对象

while (true) {
  try {
    // Get a request from the cache triage queue, blocking until
    // at least one is available.
    //1、hlwang:CacheDispatcher原料来自mCacheQueue,第一步,获得Request
    final Request<?> request = mCacheQueue.take();
    request.addMarker("cache-queue-take");
    ... ...
  }
}

2、如果Request被用户取消了,则不再需要继续执行了

// If the request has been canceled, don't bother dispatching it.
//2、hlwang:如果request已取消,已经不需要继续了
if (request.isCanceled()) {
    request.finish("cache-discard-canceled");
    continue;
}

3、优先检查缓存区,如果数据没有命中(即:数据不存在),则交给Network线程去同步数据

// Attempt to retrieve this item from cache.
//3、hlwang:如果在缓存中,不存在数据,说明是新数据,则:交给mNetworkQueue去同步新数据。
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;
}

4、如果缓存数据过期了,依旧交给Network线程去同步数据

// If it is completely expired, just send it to the network.
//4、hlwang:如果缓存过期,那么说明数据太旧了,交给mNetworkQueue去同步新数据。
if (entry.isExpired()) {
    request.addMarker("cache-hit-expired");
    request.setCacheEntry(entry);
    mNetworkQueue.put(request);
    continue;
}

5、缓存的数据被命中,则解析缓存数据,构建Response对象

// We have a cache hit; parse its data for delivery back to the request.
//5、wanghailu:我们命中了一条缓存数据(w找到了一个保质期内的缓存hl),解析数据并构建响应对象Response。
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
        new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");

6、如果缓存数据,不需要刷新,则将响应数据,通过Delivery回调给用户

if (!entry.refreshNeeded()) {
    // Completely unexpired cache hit. Just deliver the response.
    //6、如果entry数据不需要刷新,则使用mDelivery将响应传递出去
    mDelivery.postResponse(request, response);
} 

7、缓存的数据需要再次更新,那么现将缓存数据返回给用户,接着通过主线程发起同步数据请求

    // Soft-expired cache hit. We can deliver the cached response,
    // but we need to also send the request to the network for
    // refreshing.
    //7、虽然被缓存命中,但数据轻微过期。我们可以将缓存响应数据传递分发,
    //但我们同样需要将请求发送到mNetworkQueue去刷新、更新。
    request.addMarker("cache-hit-refresh-needed");
    request.setCacheEntry(entry);

    // Mark the response as intermediate.
    //7.1、更新response状态为  媒介
    response.intermediate = true;

    // Post the intermediate response back to the user and have
    // the delivery then forward the request along to the network.
    //7.2、主线程分发
    mDelivery.postResponse(request, response, new Runnable() {
        @Override
        public void run() {
            try {
                mNetworkQueue.put(request);
            } catch (InterruptedException e) {
                // Not much we can do about this.
            }
        }

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

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

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

作者:hailushijie 发表于2017/7/30 13:30:57 原文链接
阅读: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>