当前位置: 首页 > 工具软件 > ASimpleCache > 使用案例 >

ASimpleCache (ACache)缓存框架

邓俊英
2023-12-01

一,概述

官方介绍:ASimpleCache是一个为Android定制的轻量级的,开源缓存框架。轻量级到

只有一个Java类(由十几个类精简而来)。

1,它可以缓存什么对象?

普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。

2,它有什么特色?

(1), 轻,轻到只有一个java类。

(2), 可配置,可以配置缓存路径,缓存大小,和缓存数量等。

(3), 可以设置缓存的超时时间,超时自动失效,并删除。

(4), 支持多进程。

3,它在Android有哪些使用场景?

(1), 可以替换SharePreference,当做配置文件。

(2), 可以缓存网络请求数据。


二,使用分析

1,缓存String

        //初始化ACache
	mCache = ACache.get(this);
	//保存数据
	mCache.put("testString", mEt_string_input.getText().toString());
	//读取缓存
	String testString = mCache.getAsString("cachekey");

2,缓存JsonObject

	mCache = ACache.get(this);
	jsonObject = new JSONObject();
	try {
	      jsonObject.put("name", "Yoson");
	      jsonObject.put("age", 18);
	} catch (JSONException e) {
	      e.printStackTrace();
	}
	mCache.put("testJsonObject", jsonObject);//保存缓存
        JSONObject testJsonObject = mCache.getAsJSONObject("testJsonObject");//读取缓存

3,缓存JsonArrayObject,Bitmap,Drawable,JsonObject与前面类似,只是

读取时调用不同的readxxx()方法。

4,缓存Media,网络文件。

ostream = mCache.put(CACHE_KEY);//获取流,然后通过流执行写操作。
stream = mCache.get(CACHE_KEY); //获取流对象

     

三,源码分析

1,获取缓存实例

public static ACache get(Context ctx) {
	return get(ctx, "ACache");
}

public static ACache get(Context ctx, String cacheName) {
	File f = new File(ctx.getCacheDir(), cacheName);
	return get(f, MAX_SIZE, MAX_COUNT);
}

public static ACache get(File cacheDir, long max_zise, int max_count) {
	ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid());
	if (manager == null) {
		manager = new ACache(cacheDir, max_zise, max_count);
		mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager);
	}
	return manager;
}

设定了缓存目录为:/data/data/app-package-name/cache/ACache

MAX_SIZE,MAX_COUNT,表示缓存的最大存储量和缓存文件的最大个数。

Map<String, ACache> mInstanceMap,Key为缓存路径(cacheDir.getAbsoluteFile)+ 进程id(myPid)

,初次调用get方法,manager为null, 所以会创建ACache实例,并存入mInstanceMap。


接着我们看ACache的构造方法:

	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);
	}

。ACache的构造方法是私有的,因此只能通过get方法来获取ACache实例

。cacheDir(缓存目录)不存在,并且创建失败,则抛出异常

。实例化缓存管理器ACacheManager。


再接着看缓存管理器的构造方法:

		private ACacheManager(File cacheDir, long sizeLimit, int countLimit) {
			this.cacheDir = cacheDir;
			this.sizeLimit = sizeLimit;
			this.countLimit = countLimit;
			cacheSize = new AtomicLong();
			cacheCount = new AtomicInteger();
			calculateCacheSizeAndCacheCount();
		}



		/**
		 * 计算 cacheSize和cacheCount
		 */
		private void calculateCacheSizeAndCacheCount() {
			new Thread(new Runnable() {
				@Override
				public void run() {
					int size = 0;
					int count = 0;
					File[] cachedFiles = cacheDir.listFiles();
					if (cachedFiles != null) {
						for (File cachedFile : cachedFiles) {
							size += calculateSize(cachedFile);
							count += 1;
							lastUsageDates.put(cachedFile, cachedFile.lastModified());
						}
						cacheSize.set(size);
						cacheCount.set(count);
					}
				}
			}).start();
		}

。calculateCacheSizeAndCacheCount,遍历文件夹下所有的文件,计算文件的总大小和总数量。


2,往缓存实例存入数据

	/**
	 * 保存 String数据 到 缓存中
	 * 
	 * @param key
	 *            保存的key
	 * @param value
	 *            保存的String数据
	 * @param saveTime
	 *            保存的时间,单位:秒
	 */
	public void put(String key, String value, int saveTime) {
		put(key, Utils.newStringWithDateInfo(saveTime, value));
	}
。保存数据value,并且指定保存的时长saveTime
	/**
	 * 保存 String数据 到 缓存中
	 * 
	 * @param key
	 *            保存的key
	 * @param value
	 *            保存的String数据
	 */
	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);
		}
	}


	private File newFile(String key) {
		return new File(cacheDir, key.hashCode() + "");
	}


		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);
		}


。根据key新建一个文件File,并且将value值写入File(文件名就是key的hashCode + "")。

。mCache.put(File)方法:数量(cacheCount)超标,移除一个文件removeNext;大小(curCacheSize + valueSize)超标,

移除一个文件removeNext。并且lastUsageDates,记录新文件。


查看removeNext

		/**
		 * 移除旧的文件
		 * 
		 * @return
		 */
		private long removeNext() {
			if (lastUsageDates.isEmpty()) {
				return 0;
			}

			Long oldestUsage = null;
			File mostLongUsedFile = null;
			Set<Entry<File, Long>> entries = lastUsageDates.entrySet();
			synchronized (lastUsageDates) {
				for (Entry<File, Long> 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;
		}

。for循环选择出,最久没用的文件,作为待删除的文件。

。calculateSize,计算出待删文件的大小。


3,从缓存中读取数据。

	/**
	 * 读取 String数据
	 * 
	 * @param key
	 * @return String 数据
	 */
	public String getAsString(String key) {
		File 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);
		}
	}

。File file = mCache.get(key);前面保存数据的时候也出现了的,根据key值,获得指定的File。

。Utils..isDue(readString)判断文件是否过期,这和前面指定文件保存时间对应。

。最后返回去除时间信息的纯Value:return Utils.clearDataInfo(readString);


参考:http://blog.csdn.net/zhoubin1992/article/details/46379055

资源下载:https://github.com/yangfuhai/ASimpleCache

 类似资料: