Android开发之ImageLoader本地缓存
ImageLoader是一个图片缓存的开源库,提供了强大的图片缓存机制,很多开发者都在使用,今天给大家介绍Android开发之ImageLoader本地缓存,具体内容如下所示:
本地缓存在缓存文件时对文件名称的修改提供了两种方式,每一种方式对应了一个Java类
1)HashCodeFileNameGenerator,该类负责获取文件名称的hashcode然后转换成字符串。
2)Md5FileNameGenerator,该类把源文件的名称同过md5加密后保存。
两个类都继承了FileNameGenerator接口
在DefaultConfigurationFactory类中提供了一个工厂方法createFileNameGenerator,该方法返回了一个默认的FileNameGenerator对象:HashCodeFileNameGenerator.
publicstaticFileNameGeneratorcreateFileNameGenerator(){ returnnewHashCodeFileNameGenerator(); }
实现
首先定义了DiscCacheAware接口,该接口提供了如下方法
FilegetFileDectory()返回磁盘缓存的根目录 Fileget(StringimageUri)根据uri从缓存中获取图片 booleansave(StringimageUri,InputStreamiamgeStream,IoUtils.CopyListenerlistener)把图片保存在磁盘缓存上 booleansave(StringimageUri,Bitmapbitmap)保存bitmap对象到磁盘缓存上 booleanremove(imageUri)根据imageUri删除文件 voidclose()关闭磁盘缓存,释放资源 voidclear()清空磁盘缓存
然后定义了另外一个没方法的接口DiskCache,该接口只是简单的继承了DiscCacheAware接口。
BaseDiscCache实现了DiskCache,该类是个抽象类,该类定义了磁盘缓冲区的以下的属性:
1)默认的缓存大小为32k
2)默认压缩后的图片格式为PNG(作为Bitmap的compress方法的第一个参数)
3)默认压缩后图片显示的质量为100,也就是压缩率为0,不进行压缩(作为compress的第二个参数)
提供了修改压缩图片格式和压缩率以及修改缓存大小的set方法。同时该类还封装了以下三个属性
protectedfinalFilecacheDir;//缓存文件的保存Directory protectedfinalFilereserveCacheDir;//后备缓存的Diectory,当cacheDir不存在的情况下就是用reserveCahceDir后备缓存 protectedfinalFileNameGeneratorfileNameGenerator;//文件名名称生成器
构造函数
publicBaseDiscCache(FilecacheDir){ this(cacheDir,null); } publicBaseDiscCache(FilecacheDir,FilereserveCacheDir){ this(cacheDir,reserveCacheDir,DefaultConfigurationFactory.createFileNameGenerator()); } publicBaseDiscCache(FilecacheDir,FilereserveCacheDir,FileNameGeneratorfileNameGenerator){ if(cacheDir==null){ thrownewIllegalArgumentException("cacheDir"+ERROR_ARG_NULL); } if(fileNameGenerator==null){ thrownewIllegalArgumentException("fileNameGenerator"+ERROR_ARG_NULL); } this.cacheDir=cacheDir; this.reserveCacheDir=reserveCacheDir; this.fileNameGenerator=fileNameGenerator; }
1)只有一个参数的构造函数只初始化了cacheDir,没有用到后备缓存,且是以HashCodeFileNameGenerator来生成目标文件的文件名。
2)两个参数的构造器除了cacheDir和HashCodefileNameGenerator外,也可以初始化后备缓存
3)三个参数的构造器要求必须初始化cacheDir并且必须初始化filenNameGenerator否则就报异常
get(StringimageUri)
protectedFilegetFile(StringimageUri){ StringfileName=fileNameGenerator.generate(imageUri); Filedir=cacheDir; if(!cacheDir.exists()&&!cacheDir.mkdirs()){ if(reserveCacheDir!=null&&(reserveCacheDir.exists()||reserveCacheDir.mkdirs())){ dir=reserveCacheDir; } } returnnewFile(dir,fileName); }
save(StringimageUri,Bitmapbitmap)
publicbooleansave(StringimageUri,Bitmapbitmap)throwsIOException{ //获取imageUri的File对象,该对象封装了缓存路径和图片保存后的名称 FileimageFile=getFile(imageUri); //获取临时保存文件的tmpFile对象 FiletmpFile=newFile(imageFile.getAbsolutePath()+TEMP_IMAGE_POSTFIX); OutputStreamos=newBufferedOutputStream(newFileOutputStream(tmpFile),bufferSize); booleansavedSuccessfully=false; try{ //调用compress把bitMap压缩到tempFile中 savedSuccessfully=bitmap.compress(compressFormat,compressQuality,os); }finally{ IoUtils.closeSilently(os); //如果保存成功并且tempFile的文件没有成功移动到imageFile的话,就删除temFile if(savedSuccessfully&&!tmpFile.renameTo(imageFile)){ savedSuccessfully=false; } if(!savedSuccessfully){ tmpFile.delete(); } } //对bitmap进行垃圾回收 bitmap.recycle(); returnsavedSuccessfully; }
BaseDiscCache有两个扩展类,一个是不限制缓存大小的UnlimitedDiscCache和限制缓存时间的LimitedAgeDiscCache,其中UnlimitedDiscCache很简单它只是简单的继承了BaseDiscCache并未对BaseDiscCache做任何扩展。
LimitedAgeDiscCache该类实现了在缓存中删除被加载超过规定时间的文件:满足以下条件的时候就从缓存中删除文件:系统当前时间-文件的最新修改时间>maxFileAge
LimitedAgeDiscCache
该类提供了两个属性:
1.maxFileAge(long)设置加载的超时的最大时间,改时间在构造器冲初始化,一经初始化就不能改变(设定文件存活的最长时间,当超过这个值,就删除该文件)
2.loadingDates(Map<File,long>),该属性是一个map类型的对象,key保存的要缓存的图片文件,而value保存的是调用save方法是系统的当前时间,具体向loadingDates填充数据是在下面的rememberUsage方法中实现的,该方法在类中两个save方法中调用,首先调用父类的save方法,然后在调用此方法
privatevoidrememberUsage(StringimageUri){ Filefile=getFile(imageUri); longcurrentTime=System.currentTimeMillis(); file.setLastModified(currentTime); loadingDates.put(file,currentTime); }
从缓存中获取数据的方法为get(StringimageUri)该类是重写BaseDiscDache方法,该方法从loadingDates中获取imageUri所代表的图片的最新更新时间loadingDate,然后拿当前时间和loadingDate做差,如果差值大于maxFileAge也就是说查过了加载的最大时间,就删除该imageUri所代表的file,并从loadingDates中的数据,当然如果map中没有imageUri就不会涉及到超时的问题,此时就把image放入map中去,具体的实现如下
@Override publicFileget(StringimageUri){ Filefile=super.get(imageUri); if(file!=null&&file.exists()){ booleancached; LongloadingDate=loadingDates.get(file); if(loadingDate==null){ cached=false; loadingDate=file.lastModified(); }else{ cached=true; } if(System.currentTimeMillis()-loadingDate>maxFileAge){ file.delete(); loadingDates.remove(file); }elseif(!cached){ loadingDates.put(file,loadingDate); } } returnfile; }