详细讲解Android的图片下载框架UniversialImageLoader之磁盘缓存的扩展(二)

相对于第一篇来讲,这里讲的是磁盘缓存的延续。在这里我们主要是关注四个类,分别是DiskLruCache、LruDiskCache、StrictLineReader以及工具类Util。

接下来逐一的对它们进行剖析。废话不多说。

首先来看一下DiskLruCache。

这个类的主要功能是什么呢?我们先来看一段类的注释:

 /**
 * A cache that uses a bounded amount of space on a filesystem. Each cache
 * entry has a string key and a fixed number of values. Each key must match
 * the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences,
 * accessible as streams or files. Each value must be between {@code 0} and
 * {@code Integer.MAX_VALUE} bytes in length.
 * <p>This class is tolerant of some I/O errors. If files are missing from the
 * filesystem, the corresponding entries will be dropped from the cache. If
 * an error occurs while writing a cache value, the edit will fail silently.
 * Callers should handle other problems by catching {@code IOException} and
 * responding appropriately.
 */

对英文不感兴趣的童鞋别急,下面稍微翻译一下:

这是基于文件系统所构建的一个基于有限空间的缓存。每一个缓存入口都有一个字符串秘钥与固定的数字的序列。每一个秘钥一定要与正则表达式<strong>[a-z0-9_-]{1,64}</strong>进行匹配。数值则是一些字节序列,是可以作为流或者文件被访问的。每一个数值在长度上一定是在0与最大的整数之间的。这个缓存类对部分的I/O操作室容忍的。如果有一些文件从文件系统中丢失,相应的缓存的入口?会从缓存中移除。如果在写入一个缓存的数值的时候发生了以外的错误,

当前的编辑也会默默的撤销,回调者则会通过捕获一些I/O异常与核实的回应来处理一些其他的问题。

由于DiskLruCache的代码量较多,我们还是从一些核心的变量与方法上来讲述它。核心变量如下:

	static final String JOURNAL_FILE = "journal";
	static final String JOURNAL_FILE_TEMP = "journal.tmp";
	static final String JOURNAL_FILE_BACKUP = "journal.bkp";
	static final String MAGIC = "libcore.io.DiskLruCache";
	static final String VERSION_1 = "1";
	static final long ANY_SEQUENCE_NUMBER = -1;
	static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}");
	private static final String CLEAN = "CLEAN";
	private static final String DIRTY = "DIRTY";
	private static final String REMOVE = "REMOVE";
	private static final String READ = "READ";
	private final File directory;
	private final File journalFile;
	private final File journalFileTmp;
	private final File journalFileBackup;
	private final int appVersion;
	private long maxSize;
	private int maxFileCount;
	private final int valueCount;
	private long size = 0;
	private int fileCount = 0;
	private Writer journalWriter;
	private final LinkedHashMap<String, Entry> lruEntries =
			new LinkedHashMap<String, Entry>(0, 0.75f, true);
	private int redundantOpCount;
	private long nextSequenceNumber = 0;
	final ThreadPoolExecutor executorService =
			new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());

上面的变量大致进行归类,包括:日志文件的命名,日志文件的开始5行内容的变量的定义,文件尺寸与数量的限制以及一个LinkedHashMap来维持一个缓存队列,最后还有一个线程池。

接下来大致介绍一下里面的函数的功能:

1、readJournal  这个函数的功能是1、计算当前的日志的缓存的行数、2、计算当前的缓存的日志文件中冗余的行数  3、读取并且处理缓存的日志中的每一行的数据

2、readJournalLine 这个函数的功能是真正的执行每一行日志的操作   当在日志中遇到一个关键字的时候,从当前的缓存的度列中查看当前的关键字所映射的对象是否存在,如果不存在,以当前的关键字创建一个新的对象并且放到当前的缓存的队列中。

3、processJournal  计算初始化的尺寸,并且回收缓存中的一些垃圾。脏的入口将会被认为是前后矛盾的,将会被回收。

4、rebuildJournal 这个函数的功能是创建一个新的删除大量冗余信息的日志文件,如果当前的日志文件存在,将会替换掉当前的日志文件。

5、

public synchronized Snapshot get(String key) throws IOException

这个函数的功能是返回一个命名为key的文件入口的快照。并且如果当前的数值是返回的,那么它将会被移动到LRU队列的头部。

6、

public synchronized boolean remove(String key) throws IOException

如果当前的文件实体是存在的并且是可以删除的,那么就删除当前的文件的实体。当前正在被编辑的文件实体是不能够被删除的。

接下来关注一下这个类中的三个比较重要的内部类,分别是Snapshot、Editor与Entry。

大致介绍一些这三个类的功能。

Snapshot是缓存的文件实体的数值的一个快照。Editor是编辑缓存的文件实体的数值。Entry是缓存的文件实体的数据模型。

接下来我们分下一下LruDiskCache这个类的主要功能。

正如这个类的名称一样,这是一个最近最久未使用的磁盘缓存。这样这个类的大致的功能我们清楚了。

我们会在这个类中看到这样一个成员变量

protected DiskLruCache cache;

由此可见当前的类,是DiskLruCache针对磁盘缓存的接口的一个适配器。不信?我们从下面的方法中可以看出:

1、

@Override
	public File getDirectory() {
		return cache.getDirectory();
	}

获取当前的缓存的目录。

2、

public File get(String imageUri) {
		DiskLruCache.Snapshot snapshot = null;
		try {
			snapshot = cache.get(getKey(imageUri));
			return snapshot == null ? null : snapshot.getFile(0);
		} catch (IOException e) {
			L.e(e);
			return null;
		} finally {
			if (snapshot != null) {
				snapshot.close();
			}
		}
	}

通过图片的uri的对象获取图片文件的句柄。  是通过DiskLruCache中的快照实现的。

3、

public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
		DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
		if (editor == null) {
			return false;
		}

		OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
		boolean copied = false;
		try {
			copied = IoUtils.copyStream(imageStream, os, listener, bufferSize);
		} finally {
			IoUtils.closeSilently(os);
			if (copied) {
				editor.commit();
			} else {
				editor.abort();
			}
		}
		return copied;
	}

利用的是DiskLruCache中的文件编辑类Editor来讲当前的文件输入流写到生成的文件中。

其余的函数也是以此类推。

接下来要讲的类StrictLineReader,我们也是可将将其理解为一个帮助类,它是专门为读取缓存日志的内容而特别设计的。

主要观察下面的一个方法:

public String readLine() throws IOException {
		synchronized (in) {
			if (buf == null) {
				throw new IOException("LineReader is closed");
			}
			if (pos >= end) {
				fillBuf();
			}
			for (int i = pos; i != end; ++i) {
				if (buf[i] == LF) {
					int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
					String res = new String(buf, pos, lineEnd - pos, charset.name());
					pos = i + 1;
					return res;
				}
			}
			ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
				@Override
				public String toString() {
					int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
					try {
						return new String(buf, 0, length, charset.name());
					} catch (UnsupportedEncodingException e) {
						throw new AssertionError(e); // Since we control the charset this will never happen.
					}
				}
			};

			while (true) {
				out.write(buf, pos, end - pos);
				// Mark unterminated line in case fillBuf throws EOFException or IOException.
				end = -1;
				fillBuf();
				for (int i = pos; i != end; ++i) {
					if (buf[i] == LF) {
						if (i != pos) {
							out.write(buf, pos, i - pos);
						}
						pos = i + 1;
						return out.toString();
					}
				}
			}
		}
	}

在最后一个类Util中,主要是封装了三个方法,

1、readFully  从Reader中读取内容,并且拼接成为一个完整的字符串

2、deleteContents 迭代删除文件的目录的内容

3、closeQuietly 静默关闭文件流

Ok,关于磁盘存储的扩展就讲到这里,希望对各位童鞋有所帮助。

时间: 2024-08-27 11:54:26

详细讲解Android的图片下载框架UniversialImageLoader之磁盘缓存的扩展(二)的相关文章

详细讲解Android的图片下载框架UniversialImageLoader之磁盘缓存(一)

沉浸在Android的开发世界中有一些年头的猴子们,估计都能够深深的体会到Android中的图片下载.展示.缓存一直是心中抹不去的痛.鄙人亦是如此.Ok,闲话不说,为了督促自己的学习,下面就逐一的挖掘Android中还算是比较牛叉的图片处理框架UniversialImageLoader以飨读者吧! 凡事如果过于草率必将陷入泥塘不能自拔.还是按部就班的一步一步的将这个框架给啃透. 第一个要讲的是磁盘的缓存的接口DiskCache 首先看一下其中的核心的接口的代码: File getDirector

详细讲解Android图片下载框架UniversialImageLoader之内存缓存扩展(四)

内存缓存的扩展还是蛮重要的,无论是数据结构还是具体的实现还是值得我们进行细细的品味,下面咱们就一起能品味这里面的趣味吧. 内存缓存的扩展主要学习下面的几个类:FIFOLimitedMemoryCache.FuzzyKeyMemoryCache. LargestLimitedMemoryCache.LimitedAgeMemoryCache.LRULimitedMemoryCache. LruMemoryCache.UsingFreqLimitedMemoryCache以及WeakMemoryCa

详细讲解Android图片下载框架UniversialImageLoader之内存缓存(三)

前面的两篇文章着重介绍的是磁盘缓存,这篇文章主要是讲解一下内存缓存.对于内存缓存,也打算分两篇文章来进行讲解.在这一篇文章中,我们主要是关注三个类, MemoryCache.BaseMemoryCache以及LimitedMemoryCache. 首先我们先看一下内存缓存的接口MemoryCache. [java] view plaincopyprint? put(String key, Bitmap value); Bitmap get(String key); Bitmap remove(S

具体解说Android图片下载框架UniversialImageLoader之内存缓存(三)

前面的两篇文章着重介绍的是磁盘缓存,这篇文章主要是解说一下内存缓存.对于内存缓存.也打算分两篇文章来进行解说.在这一篇文章中,我们主要是关注三个类, MemoryCache.BaseMemoryCache以及LimitedMemoryCache. 首先我们先看一下内存缓存的接口MemoryCache. put(String key, Bitmap value); Bitmap get(String key); Bitmap remove(String key); Collection<Strin

Android 多线程多任务下载框架的实现(一)

什么是多线程多任务下载框架: Android 多线程多任务下载框架 封装了一个下载工具类,该下载工具支持多线程下载,下载任务队列,下载进度更新,取消下载等.可用于应用市场app的下载,音乐下载等. 为什么需要多线程多任务下载框架: 我们在开发Android 应用市场的时候需要下载apk,这个时候用户希望能同时下载多个apk并且显示正确的进度条信息,且下载速度快,那么我们就需要多线程多任务下载框架来支持这些功能,来达到很好的用户体验. 怎么实现多线程多任务下载框架: 涉及到的知识点: 1.线程操作

详细讲解Android的网络通信(HttpUrlConnection和HttpClient)

前言,Android的网络通信的方式有两种:使用Socket或者HTTP,今天这一篇我们详细讲解使用HTTP实现的网络通信,HTTP又包括两种方式编程方式: (1)HttpUrlConnection: (2)HttpClient: 好了,我们直接进行讲解,当然之前也会有一部分有关Android网络通信的其他知识,我们也应该了解. 一.获取网络状态的方法 (1)MainActivity.java中的关键代码 1 2 3 4 5 6 7 8 //网络管理类,可以判断是否能上网,以及网络类型     

猫猫学iOS(五十五)多线程网络之图片下载框架之SDWebImage

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243?viewmode=contents 效果: 代码: - (NSArray *)apps { if (!_apps) { NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil

详细讲解Android对自己的应用代码进行混淆加密防止反编译

1.查看项目中有没有proguard.cfg. 2.如果没有那就看看这个文件中写的什么吧,看完后将他复制到你的项目中. -optimizationpasses 5 -dontusemixedcaseclassnames -dontskipnonpubliclibraryclasses -dontpreverify -verbose -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* -keep publ

Android学习笔记之详细讲解画圆角图片

[java] view plain copy package xiaosi.RoundConcer; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Pain