Volley框架的基本解读(五)

来源:互联网 发布:网络著作权侵权 编辑:程序博客网 时间:2024/06/07 06:54

在之前四篇博客中,我们已经将RequestQueue中start方法中的网络请求这条主线完全解析了一遍,接下来我们看另一条缓存主线,CacheDispatcher的源码:


public class CacheDispatcher extends Thread

同NetworkDispatcher一样,CacheDispatcher同样是一个线程


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

里面也只有一个构造方法,四个参数分别是缓存队列,网络队列,缓存处理类,结果分发类,同样的在RequestQueue调用了它的start方法,因为是Thread所以我们看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.            // 从缓存队列中取出request                final Request request = mCacheQueue.take();                // 调试信息                request.addMarker("cache-queue-take");                // If the request has been canceled, don't bother dispatching it.                // 如果该request以取消,则中断任务                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解析,并输出调试日志                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;            }        }    }

该方法首先初始化了缓存数据,让我们进入mCache.initialize方法里面看看,这里说一点Cache同Network一样是一个接口,里面的方法稍微多一点,我们来看具体子类实现,同样是在Volley.newRequestQueue中创建的:


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


接着看


public DiskBasedCache(File rootDirectory) {        this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);    }


public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) {        mRootDirectory = rootDirectory;        mMaxCacheSizeInBytes = maxCacheSizeInBytes;    }

rootDirectory是缓存径路,DEFAULT_DISK_USAGE_BYTES默认值是5 * 1024 * 1024,也就是5M,表示最大缓存容量。


我们来看看它的initialize方法:


/**     * Initializes the DiskBasedCache by scanning for all files currently in the     * specified root directory. Creates the root directory if necessary.     *      * 初始化缓存,将缓存文件全部读入内存中     */    @Override    public synchronized void initialize() {    // 如果文件不存在,说明无缓存        if (!mRootDirectory.exists()) {            if (!mRootDirectory.mkdirs()) {                VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath());            }            return;        }        // 获取缓存文件数组        File[] files = mRootDirectory.listFiles();        if (files == null) {            return;        }        for (File file : files) {            FileInputStream fis = null;            try {                fis = new FileInputStream(file);                CacheHeader entry = CacheHeader.readHeader(fis);                entry.size = file.length();                putEntry(entry.key, entry);            } catch (IOException e) {                if (file != null) {                   file.delete();                }            } finally {                try {                    if (fis != null) {                        fis.close();                    }                } catch (IOException ignored) { }            }        }    }

前面很简单,判断缓存路径是否存在,否创建缓存路径,如果创建失败,那么初始化也就失败了。


然后获取缓存路径下的所有缓存文件,用字节流读取解析,CacheHeader是DiskBasedCache中的静态内部类,里面定义了很多字段,比如size数据长度,key缓存的键,其实就是URL,还有serverDate服务器的返回时间等等,readHeader方法就是对读取缓存文件进行了封装,考虑到涉及到的方法太多,我就不一一贴出来了,得到了CacheHeader这个缓存实体,putEntry方法就是将它放入内存:


/**     * Puts the entry with the specified key into the cache.     * @param key The key to identify the entry by.     * @param entry The entry to cache.     *      * 将缓存读入内存     */    private void putEntry(String key, CacheHeader entry) {    // 如果内存中没有该缓存,累加当前缓存大小,如果存在,计算缓存容量差,再进行累计        if (!mEntries.containsKey(key)) {            mTotalSize += entry.size;        } else {            CacheHeader oldEntry = mEntries.get(key);            mTotalSize += (entry.size - oldEntry.size);        }        mEntries.put(key, entry);    }

mEntries是一个Map集合,定义在DiskBasedCache的成员变量中


/** Map of the Key, CacheHeader pairs 初始位16,扩展0.75倍,使用排序*/    private final Map<String, CacheHeader> mEntries =            new LinkedHashMap<String, CacheHeader>(16, .75f, true);

initialize方法我们分析完了,回过头继续看CacheDispatcher的run方法,同NetworkDispatcher一样的写法,后面也是一个while死循环,mCacheQueue同样是一个优先级队列,试图从队列中获取一个request,判断request是否取消,是结束该次请求,request.getCacheKey()返回的就是URL,试图从缓存中查找对应的缓存,如果找不到,扔进网络队列中,它就不管了,如果获取到的缓存已经过期,还是扔进网络队列,当个甩手掌柜,到这里可以确定缓存有效,封装成Response准备返回,下面这个!entry.refreshNeeded()对缓存过期的再次判断,是我也不太理解的地方,但代码是很清晰的,如果没有过期,分发结果,如果过期了,它依然会返回结果,但会向网络请求一次,也就是说,该request会得到两个response,一个是缓存的,一个是网络的。


到这里大家可能已经急不可待想揭开mDelivery的神秘面纱了,但我们下一篇再说,在CacheDispatcher还有一个我们熟悉的方法:


/**     * Forces this dispatcher to quit immediately.  If any requests are still in     * the queue, they are not guaranteed to be processed.     *      * 标记退出,并中断线程     */    public void quit() {        mQuit = true;        interrupt();    }

作用就不必我多说了吧,我们下篇博客再见!


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 奶黄馅没有澄粉怎么办 情侣买房分手了怎么办 没有好的扇面怎么办? 小孩上学成绩差怎么办 钥匙丢了锁打不开怎么办 钥匙丢了门打不开怎么办 电脑软件无响应怎么办 移动浏览不了91怎么办 12360注册过了怎么办 微信应用打不开怎么办 微信应用信息怎么办 3位密码箱打不开怎么办 苹果6看视频卡怎么办 苹果6手机打不开怎么办 苹果ip停用了怎么办 苹果手机以停用怎么办 微信视频卡顿怎么办 微信发视频太慢怎么办 手机微信小视频打不开怎么办 移动客服态度差怎么办 地下城不能下载怎么办 dnf安装文件失败怎么办 dnf安装游戏失败怎么办 电脑提示文件损坏怎么办 手机刷机失灵怎么办 刷机时安装终止怎么办 牛发烧40度怎么办 mac所有程序打不开怎么办 苹果iphonex掉了怎么办 空调送错货安装完怎么办 联想电脑打不开机怎么办 联想电脑开不开机怎么办 笔记本声音没有了怎么办 升级后信号不好怎么办? 金融公司倒闭钱怎么办 海尔冰箱不通电怎么办 小区宽带被垄断怎么办 美术生家里没钱怎么办 skg补水仪堵塞了怎么办 榨汁机不会动了怎么办 电水壶有塑料味怎么办