編輯:關於Android編程
Android-Universal-Image-Loader是一個開源項目,負責處理圖片的加載和緩存。閒暇之時看了一些源代碼,特記錄之。
說道圖片文件(磁盤)緩存,需要考慮如下的因素
1) 緩存文件的名稱的定義
2) 緩存的大小
3) 緩存文件的方式:比如限時保存文件等,圖片壓縮後的格式,壓縮率等等。
該項目對磁盤緩存保存文件時對文件名稱的修改也做了支持:在緩存文件時對文件名稱的修改提供了兩種方式,每一種方式對應了一個Java類
1) HashCodeFileNameGenerator,該類負責獲取文件名稱的hashcode然後轉換成字符串。
2) Md5FileNameGenerator,該類把源文件的名稱同過md5加密後保存。兩個類都繼承了FileNameGenerator接口
它們之間的關系如下圖所示
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHAgYWxpZ249"left">在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;//緩存文件的保存Directory protected 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的話,就刪除temFile if (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
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中去,具體的實現如下
@Override public 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; }
在上一篇教程中,主要介紹了如何把OSG源代碼編譯成為能夠在Android項目下使用的函數庫。在這一篇教程中,我將針對如何在自己的Android項目中配置OSG函數庫進行詳
主程序: public class WebPageLoader extends Activity{ final Activity activit
Auticompelete TextView動態匹配輸入的內容:目的,動態匹配輸入的內容,如百度搜索引擎當輸入文本時可以根據內容顯示匹配的熱門信息。一.目的效果圖:實驗效
本文主要介紹Android應用程序簽名的相關理論知識以及如何發布Android應用程序。 1.簽名的概念 為大家所熟知的日常生活中的簽名,它是代表某個人的特殊標記,用