Android-Universal-Image-Loader学习笔记(一)

来源:互联网 发布:淘宝文艺女装品牌 编辑:程序博客网 时间:2024/06/10 02:55

Android-Universal-Image-Loader是一个开源项目,负责处理图片的加载和缓存。闲暇之时看了一些源代码,特记录之。

说道图片文件(磁盘)缓存,需要考虑如下的因素

1)  缓存文件的名称的定义

2)  缓存的大小

3)  缓存文件的方式:比如限时保存文件等,图片压缩后的格式,压缩率等等。

该项目对磁盘缓存保存文件时对文件名称的修改也做了支持:在缓存文件时对文件名称的修改提供了两种方式,每一种方式对应了一个Java类

1)  HashCodeFileNameGenerator,该类负责获取文件名称的hashcode然后转换成字符串。

2)  Md5FileNameGenerator,该类把源文件的名称同过md5加密后保存。两个类都继承了FileNameGenerator接口

它们之间的关系如下图所示

在DefaultConfigurationFactory类中提供了一个工厂方法createFileNameGenerator,该方法返回了一个默认的FileNameGenerator对象:HashCodeFileNameGenerator.

public static FileNameGenerator createFileNameGenerator() {return new HashCodeFileNameGenerator();}

下面说说磁盘缓存的具体实现:

    首先定义了DiscCacheAware接口,该接口提供了如下方法

方法名

说明

返回值

getFileDectory()

返回磁盘缓存的根目录

File

get(String imageUri)

根据uri从缓存中获取图片

File

save(imageUri,InputStream iamgeStream,IoUtils.CopyListener listener)

把图片保存在磁盘缓存上

boolean

save(imageUri,Bitmap bitmap)

保存bitMap对象到磁盘缓存上

Boolean

remove(imageUri)

根据imageUri删除文件

boolean

close()

关闭磁盘缓存,释放资源

void

clear()

清空磁盘缓存

void

 然后定义了另外一个没方法的接口DiskCache(这个接口名称应该命名为DiscCache比较好),该接口只是简单的继承了DiscCacheAware接口

 BaseDiscCache实现了DiskCache,该类是个抽象类(定义为抽象类的好处之一就是没必要全部重写DiskCacheAware接口提供的方法),该类定义了磁盘缓冲区的以下的(默认)属性:

1)  默认的缓存大小为32k

2)  默认压缩后的图片格式为PNG(作为Bitmap的compress方法的第一个参数)

3)  默认压缩后图片显示的质量为100,也就是压缩率为0,不进行压缩(作为compress的第二个参数)

当然该类也提供了修改压缩图片格式和压缩率以及修改缓存大小的set方法。同时该类还封装了以下三个属性

protected final File cacheDir;//缓存文件的保存Directoryprotected final File reserveCacheDir;//后备缓存的Diectory,当cacheDir不存在的情况下就是用reserveCahceDir后备缓存protected final FileNameGenerator fileNameGenerator;//文件名名称生成器

该类提供了三个构造函数

1)  只有一个参数的构造函数只初始化了cacheDir,没有用到后备缓存,且是以HashCodeFileNameGenerator来生成目标文件的文件名。

2)  两个参数的构造器除了cacheDir和HashCodefileNameGenerator外,也可以初始化后备缓存

3)  三个参数的构造器要求必须初始化cacheDir并且必须初始化filenNameGenerator否则就报异常

三个构造器的代码如下

public BaseDiscCache(File cacheDir) {this(cacheDir, null);}public BaseDiscCache(File cacheDir, File reserveCacheDir) {this(cacheDir, reserveCacheDir, DefaultConfigurationFactory.createFileNameGenerator());}public BaseDiscCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {if (cacheDir == null) {throw new IllegalArgumentException("cacheDir" + ERROR_ARG_NULL);}if (fileNameGenerator == null) {throw new IllegalArgumentException("fileNameGenerator" + ERROR_ARG_NULL);}this.cacheDir = cacheDir;this.reserveCacheDir = reserveCacheDir;this.fileNameGenerator = fileNameGenerator;}

BasicDiscCache实现了除close之外的其余的六个方法,下面进行一一说明:

1)      clear():循环便利cacheDir.listFiles()的每一个File对象,然后调用File对象的delete()方法来清空缓存

2)      getDirectory():直接返回了cacheDir

3)      get(StringimageUri):该方法调用BasicCahce的一个重要方法getFile(String imageUri).

该方法如下所示(该方法在save方法中也有调用)

protected File getFile(String imageUri) {String fileName = fileNameGenerator.generate(imageUri);File dir = cacheDir;if (!cacheDir.exists() && !cacheDir.mkdirs()) {if (reserveCacheDir != null && (reserveCacheDir.exists() || reserveCacheDir.mkdirs())) {dir = reserveCacheDir;}}return new File(dir, fileName);}

4)      save(StringimageUri, Bitmap bitmap)方法的具体实现

public boolean save(String imageUri, Bitmap bitmap) throws IOException {//获取imageUri的File对象,该对象封装了缓存路径和图片保存后的名称File imageFile = getFile(imageUri);//获取临时保存文件的tmpFile对象File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);boolean savedSuccessfully = false;try {//调用compress把bitMap压缩到tempFile中savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);} finally {IoUtils.closeSilently(os);//如果保存成功并且tempFile的文件没有成功移动到imageFile的话,就删除temFileif (savedSuccessfully && !tmpFile.renameTo(imageFile)) {savedSuccessfully = false;}if (!savedSuccessfully) {tmpFile.delete();}}//对bitmap进行垃圾回收bitmap.recycle();return savedSuccessfully;}

5)save的另外一个重载方法处理的逻辑同上,需要注意的是两个save方法当文件保存时会先生成一个tempFile然后会将调用renameTo方法将该tempFile重命名为imageFile

BaseDiscCache有两个扩展类,一个是不限制缓存大小的UnlimitedDiscCache和限制缓存时间的LimitedAgeDiscCache其中UnlimitedDiscCache很简单它只是简单的继承了BaseDiscCache并未对BaseDiscCache做任何扩展。

LimitedAgeDiscCache该类实现了在缓存中删除被加载超过规定时间的文件:满足以下条件的时候就从缓存中删除文件:系统当前时间-文件的最新修改时间》maxFileAge

该类提供了两个属性:

1.  maxFileAge(long类型)设置加载的超时的最大时间,改时间在构造器冲初始化,一经初始化就不能改变(设定文件存活的最长时间,当超过这个值,就删除该文件)

2.  loadingDates (Map<File,long>),该属性是一个map类型的对象,key保存的要缓存的图片文件,而value保存的是调用save方法是系统的当前时间,具体向loadingDates填充数据是在下面的rememberUsage方法中实现的,该方法在类中两个save方法中调用,首先调用父类的save方法,然后在调用此方法

private void rememberUsage(String imageUri) {File file = getFile(imageUri);long currentTime = System.currentTimeMillis();file.setLastModified(currentTime);loadingDates.put(file, currentTime);}

从缓存中获取数据的方法为get(String imageUri)该类是重写BaseDiscDache方法,该方法从loadingDates中获取imageUri所代表的图片的最新更新时间loadingDate,然后拿当前时间和loadingDate做差,如果差值大于maxFileAge也就是说查过了加载的最大时间,就删除该imageUri所代表的file,并从loadingDates中的数据,当然如果map中没有imageUri就不会涉及到超时的问题,此时就把image放入map中去,具体的实现如下

@Overridepublic File get(String imageUri) {File file = super.get(imageUri);if (file != null && file.exists()) {boolean cached;Long loadingDate = loadingDates.get(file);if (loadingDate == null) {cached = false;loadingDate = file.lastModified();} else {cached = true;}if (System.currentTimeMillis() - loadingDate > maxFileAge) {file.delete();loadingDates.remove(file);} else if (!cached) {loadingDates.put(file, loadingDate);}}return file;}





0 0
原创粉丝点击