android輕量級緩衝架構ASimpleCache分析
官方簡介:
ASimpleCache 是一個為android制定的 輕量級的 開源緩衝架構。輕量到只有一個java檔案(由十幾個類精簡而來)。
(有個問題是作者所說的自動失效,其實是在擷取資料時判斷存入緩衝的資料是否到期,如果到期,則刪除資料緩衝,返回null。當然,如果真正的自動刪除,應該只能開啟服務,不斷判斷是否到期來刪除吧,也沒有必要)
--------------------------------------------------------------------------------
1、它可以緩衝什麼東西?
普通的字串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java對象,和 byte資料。
2、它有什麼特色?
特色主要是:
1:輕,輕到只有一個JAVA檔案。
2:可配置,可以配置緩衝路徑,緩衝大小,緩衝數量等。
3:可以設定緩衝逾時時間,緩衝逾時自動失效,並被刪除。
4:支援多進程。
3、它在android中可以用在哪些情境?
1、替換SharePreference當做設定檔
2、可以緩衝網路請求資料,比如oschina的android用戶端可以緩衝http請求的新聞內容,緩衝時間假設為1個小時,逾時後自動失效,讓用戶端重新請求新的資料,減少用戶端流量,同時減少伺服器並發量。
3、您來說...
4、如何使用 ASimpleCache?
以下有個小的demo,希望您能喜歡:
ACache mCache = ACache.get(this);
mCache.put(test_key1, test value);
mCache.put(test_key2, test value, 10);//儲存10秒,如果超過10秒去擷取這個key,將為null
mCache.put(test_key3, test value, 2 * ACache.TIME_DAY);//儲存兩天,如果超過兩天去擷取這個key,將為null
擷取資料
ACache mCache = ACache.get(this);
String value = mCache.getAsString(test_key1);
主要分析下集萬千寵愛於一身的ACache類吧(以字串儲存為例)
一,首先先要建立緩衝
get(Context ctx, String cacheName)方法建立緩衝目錄
get(File cacheDir, long max_zise, int max_count)方法建立緩衝執行個體,存入執行個體map,key為緩衝目錄加上每次應用開啟的進程id
public static ACache get(Context ctx) {return get(ctx, ACache);}public static ACache get(Context ctx, String cacheName) {//建立緩衝目錄///data/data/com.yangfuhai.asimplecachedemo/cache/ACacheFile f = new File(ctx.getCacheDir(), cacheName);return get(f, MAX_SIZE, MAX_COUNT);}public static ACache get(File cacheDir) {return get(cacheDir, MAX_SIZE, MAX_COUNT);}public static ACache get(Context ctx, long max_zise, int max_count) {File f = new File(ctx.getCacheDir(), ACache);return get(f, max_zise, max_count);}public static ACache get(File cacheDir, long max_zise, int max_count) {///data/data/com.yangfuhai.asimplecachedemo/cache/ACacheACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid());if (manager == null) {manager = new ACache(cacheDir, max_zise, max_count);//{/data/data/com.yangfuhai.asimplecachedemo/cache/ACache_4137=org.afinal.simplecache.ACache@2bc38270}//{/data/data/com.yangfuhai.asimplecachedemo/cache/ACache_12189=org.afinal.simplecache.ACache@2bc3d890}mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager);}return manager;}private static String myPid() {return _ + android.os.Process.myPid();}private ACache(File cacheDir, long max_size, int max_count) {if (!cacheDir.exists() && !cacheDir.mkdirs()) {throw new RuntimeException(can't make dirs in + cacheDir.getAbsolutePath());}mCache = new ACacheManager(cacheDir, max_size, max_count);}
二,存入資料
put(String key, String value)方法寫資料到檔案
put(String key, String value)方法中的mCache.put(file)方法做了如下設定
檔案放入程式緩衝後,統計緩衝總量,總數,檔案存放到檔案map中(value值為檔案最後修改時間,便於根據設定的銷毀時間進行銷毀)
緩衝沒有超過限制,則增加緩衝總量,總數的數值
緩衝超過限制,則減少緩衝總量,總數的數值
通過removeNext方法找到最老檔案的大小
public void put(String key, String value) {File file = mCache.newFile(key);BufferedWriter out = null;try {out = new BufferedWriter(new FileWriter(file), 1024);out.write(value);} catch (IOException e) {e.printStackTrace();} finally {if (out != null) {try {out.flush();out.close();} catch (IOException e) {e.printStackTrace();}}mCache.put(file);}}
//檔案放入程式緩衝後,統計緩衝總量,總數,檔案存放到檔案map中(value值為檔案最後修改時間,便於根據設定的銷毀時間進行銷毀)//緩衝沒有超過限制,則增加緩衝總量,總數的數值//緩衝超過限制,則減少緩衝總量,總數的數值//通過removeNext方法找到最老檔案的大小private void put(File file) {int curCacheCount = cacheCount.get();while (curCacheCount + 1 > countLimit) {long freedSize = removeNext();cacheSize.addAndGet(-freedSize);curCacheCount = cacheCount.addAndGet(-1);}cacheCount.addAndGet(1);long valueSize = calculateSize(file);long curCacheSize = cacheSize.get();while (curCacheSize + valueSize > sizeLimit) {long freedSize = removeNext();curCacheSize = cacheSize.addAndGet(-freedSize);}cacheSize.addAndGet(valueSize);Long currentTime = System.currentTimeMillis();file.setLastModified(currentTime);lastUsageDates.put(file, currentTime);}
/** * 移除舊的檔案(冒泡,找到最後修改時間最小的檔案) * * @return */private long removeNext() {if (lastUsageDates.isEmpty()) {return 0;}Long oldestUsage = null;File mostLongUsedFile = null;Set> entries = lastUsageDates.entrySet();synchronized (lastUsageDates) {for (Entry entry : entries) {if (mostLongUsedFile == null) {mostLongUsedFile = entry.getKey();oldestUsage = entry.getValue();} else {Long lastValueUsage = entry.getValue();if (lastValueUsage < oldestUsage) {oldestUsage = lastValueUsage;mostLongUsedFile = entry.getKey();}}}}long fileSize = calculateSize(mostLongUsedFile);if (mostLongUsedFile.delete()) {lastUsageDates.remove(mostLongUsedFile);}return fileSize;}
三,擷取資料
getAsString(String key)方法從快取檔案中讀取資料,其中通過Utils.isDue(readString)方法判斷資料是否到期,是否要刪除
public String getAsString(String key) {///data/data/com.yangfuhai.asimplecachedemo/cache/ACache/1727748931File file = mCache.get(key);if (!file.exists())return null;boolean removeFile = false;BufferedReader in = null;try {in = new BufferedReader(new FileReader(file));String readString = ;String currentLine;while ((currentLine = in.readLine()) != null) {readString += currentLine;}if (!Utils.isDue(readString)) {return Utils.clearDateInfo(readString);} else {removeFile = true;return null;}} catch (IOException e) {e.printStackTrace();return null;} finally {if (in != null) {try {in.close();} catch (IOException e) {e.printStackTrace();}}if (removeFile)remove(key);}}
/** * 判斷緩衝的String資料是否到期 * * @param str * @return true:到期了 false:還沒有到期 */private static boolean isDue(String str) {return isDue(str.getBytes());}/** * 判斷緩衝的byte資料是否到期(到期:目前時間大於儲存時間加上儲存後的存留時間) * * @param data * @return true:到期了 false:還沒有到期 */private static boolean isDue(byte[] data) {String[] strs = getDateInfoFromDate(data);if (strs != null && strs.length == 2) {String saveTimeStr = strs[0];while (saveTimeStr.startsWith(0)) {saveTimeStr = saveTimeStr.substring(1, saveTimeStr.length());}long saveTime = Long.valueOf(saveTimeStr);long deleteAfter = Long.valueOf(strs[1]);if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) {return true;}}return false;}
//資料有無存留時間設定private static boolean hasDateInfo(byte[] data) {return data != null && data.length > 15 && data[13] == '-' && indexOf(data, mSeparator) > 14;} //saveDate檔案儲存時間毫秒數,deleteAfter檔案儲存後的保留時間毫秒數private static String[] getDateInfoFromDate(byte[] data) {if (hasDateInfo(data)) {String saveDate = new String(copyOfRange(data, 0, 13));String deleteAfter = new String(copyOfRange(data, 14, indexOf(data, mSeparator)));return new String[] { saveDate, deleteAfter };}return null;}