Acache缓存的使用
来源:互联网 发布:app程序员招聘要求 编辑:程序博客网 时间:2024/05/18 17:26
最近做app开发时,使用了Acache缓存来实现从网络中的图片,文本数据进行在本地存储,Android通过使用二级缓存来减少频繁的网络操作,减少流量,提升app使用的性能。
可以缓存字符串,JsonObject,,JsonArray,Bitmap,Drawable,序列化的java对象,和byte数据转化。
查阅相资料了解到Acache缓存 的特点:
1.轻量化,
2.可配置,包括配置缓存路径,缓存大小,缓存数量等。
3.可以设置缓存超时时间,缓存超时是自动失效,并被删除。
4.支持多线程
会在下文中会结合源码进行分析。
在阅读Acache源码时,使用这种数据
package com.codeest.geeknews.component; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import com.codeest.geeknews.app.Constants; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import java.io.Serializable; import java.math.BigDecimal; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * @author Michael Yang(www.yangfuhai.com) update at 2013.08.07 */ public class ACache { public static final int TIME_HOUR = 60 * 60; public static final int TIME_DAY = TIME_HOUR * 24; private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb private static final int MAX_COUNT = Integer.MAX_VALUE;// 不限制存放数据的数量 private static Map<String,ACache> mInstanceMap=new HashMap<String,ACache>(); private ACacheManager mCache; Acache缓存get基本方法//其中三个get方法是关联的,首先调用get(Context ctx),然后到get(Contextt ctx,String cachename)//最后到get(Context ctx,long size,mex_count) public static ACache get(Context ctx) { return get(ctx, "Data"); } public static ACache get(Context ctx, String cacheName) { File f = new File(Constants.PATH_DATA, 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(Constants.PATH_DATA,"Data"); return get(f, max_zise, max_count); } //新建缓存实例,存入实例map,key为缓存目录+每次应用开启的进程id public static ACache get(File cacheDir, long max_zise, int max_count) { //返回key为缓存目录+每次应用开启的进程id的map的value值,付给缓存实例manager ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile()+ myPid()); if (manager == null) {//初次运行时,当manager为空时,通过Acache构建实例,然后将该实例引用存入mInstanceMap中 manager = new ACache(cacheDir, max_zise, max_count); mInstanceMap.put(cacheDir.getAbsolutePath()+ myPid(), manager); } return manager; } public static boolean deleteDir(File dir) { if (dir != null && dir.isDirectory()) { String[] children = dir.list(); for (String aChildren: children) { boolean success = deleteDir(new File(dir, aChildren)); if (!success) { return false; } } } assert dir != null; return dir.delete(); } public static String getCacheSize(File file) { return getFormatSize(getFolderSize(file)); } public static long getFolderSize(Filefile) { long size = 0; try { File[] fileList = file.listFiles(); for (File aFileList: fileList) { // 如果下面还有文件 if (aFileList.isDirectory()) { size = size + getFolderSize(aFileList); } else { size = size + aFileList.length(); } } } catch (Exception e) { e.printStackTrace(); } return size; } public static String getFormatSize(doublesize) { double kiloByte = size / 1024; if (kiloByte < 1) { // return size + "Byte"; return "0K"; } double megaByte = kiloByte / 1024; if (megaByte < 1) { BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); return result1.setScale(2,BigDecimal.ROUND_HALF_UP) .toPlainString() + "KB"; } double gigaByte = megaByte / 1024; if (gigaByte < 1) { BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); return result2.setScale(2,BigDecimal.ROUND_HALF_UP) .toPlainString() + "MB"; } double teraBytes = gigaByte / 1024; if (teraBytes < 1) { BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); return result3.setScale(2,BigDecimal.ROUND_HALF_UP) .toPlainString() + "GB"; } BigDecimal result4 = new BigDecimal(teraBytes); return result4.setScale(2,BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; } 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); } // ======================================= // ============ String数据 读写 ============== // ======================================= /** * 保存 String数据 到 缓存中 * * @param key 保存的key * @param value 保存的String数据 */ public void put(Stringkey,String value) { File file = mCache.newFile(key); BufferedWriter out = null; try { out = new BufferedWriter(newFileWriter(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); } } /** * 保存 String数据 到 缓存中 * * @param key 保存的key * @param value 保存的String数据 * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,String value, int saveTime) { put(key, Utils.newStringWithDateInfo(saveTime, value)); } /** * 读取 String数据 * * @return String 数据 */ public String getAsString(Stringkey) { File file = mCache.get(key); if (!file.exists())returnnull; boolean removeFile = false; BufferedReader in = null; try { in = new BufferedReader(newFileReader(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); } } // ======================================= // ============= JSONObject 数据 读写 ============== // ======================================= /** * 保存 JSONObject数据 到 缓存中 * @param key 保存的key * @param value 保存的JSON数据 */ public void put(Stringkey,JSONObject value) { put(key, value.toString()); } /** * 保存 JSONObject数据 到 缓存中 * * @param key 保存的key * @param value 保存的JSONObject数据 * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,JSONObject value, int saveTime) { put(key, value.toString(), saveTime); } /** * 读取JSONObject数据 * * @return JSONObject数据 */ public JSONObject getAsJSONObject(Stringkey) { String JSONString = getAsString(key); try { JSONObject obj = new JSONObject(JSONString); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } // ======================================= // ============ JSONArray 数据 读写 ============= // ======================================= /** * 保存 JSONArray数据 到 缓存中 * * @param key 保存的key * @param value 保存的JSONArray数据 */ public void put(Stringkey,JSONArray value) { put(key, value.toString()); } /** * 保存 JSONArray数据 到 缓存中 * * @param key 保存的key * @param value 保存的JSONArray数据 * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,JSONArray value, int saveTime) { put(key, value.toString(), saveTime); } /** * 读取JSONArray数据 * * @return JSONArray数据 */ public JSONArray getAsJSONArray(Stringkey) { String JSONString = getAsString(key); try { JSONArray obj = new JSONArray(JSONString); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } // ======================================= // ============== byte 数据 读写 ============= // ======================================= /** * 保存 byte数据 到 缓存中 * * @param key 保存的key * @param value 保存的数据 */ public void put(Stringkey,byte[] value) { File file = mCache.newFile(key); FileOutputStream out = null; try { out = new FileOutputStream(file); out.write(value); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } mCache.put(file); } } /** * 保存 byte数据 到 缓存中 * * @param key 保存的key * @param value 保存的数据 * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,byte[] value, int saveTime) { put(key, Utils.newByteArrayWithDateInfo(saveTime, value)); } /** * 获取 byte 数据 * * @return byte 数据 */ public byte[] getAsBinary(Stringkey) { RandomAccessFile RAFile = null; boolean removeFile = false; try { File file = mCache.get(key); if (!file.exists())returnnull; RAFile = new RandomAccessFile(file, "r"); byte[] byteArray = new byte[(int) RAFile.length()]; RAFile.read(byteArray); if (!Utils.isDue(byteArray)) { return Utils.clearDateInfo(byteArray); } else { removeFile = true; return null; } } catch (Exception e) { e.printStackTrace(); return null; } finally { if (RAFile!=null) { try { RAFile.close(); } catch (IOException e) { e.printStackTrace(); } } if (removeFile) remove(key); } } // ======================================= // ============= 序列化 数据 读写 =============== // ======================================= /** * 保存 Serializable数据 到 缓存中 * * @param key 保存的key * @param value 保存的value */ public void put(Stringkey,Serializable value) { put(key, value, -1); } /** * 保存 Serializable数据到 缓存中 * * @param key 保存的key * @param value 保存的value * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,Serializable value,int saveTime) { ByteArrayOutputStream baos=null; ObjectOutputStream oos = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(value); byte[] data = baos.toByteArray(); if (saveTime != -1) { put(key, data, saveTime); } else { put(key, data); } } catch (Exception e) { e.printStackTrace(); } finally { try { oos.close(); } catch (IOException e) { } } } /** * 读取 Serializable数据 * * @return Serializable 数据 */ public Object getAsObject(Stringkey) { byte[] data = getAsBinary(key); if (data != null) { ByteArrayInputStream bais=null; ObjectInputStream ois = null; try { bais = new ByteArrayInputStream(data); ois = new ObjectInputStream(bais); Object reObject = ois.readObject(); return reObject; } catch (Exception e) { e.printStackTrace(); return null; } finally { try { if (bais != null) bais.close(); } catch (IOException e) { e.printStackTrace(); } try { if (ois != null) ois.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } // ======================================= // ============== bitmap 数据 读写 ============= // ======================================= /** * 保存 bitmap 到 缓存中 * * @param key 保存的key * @param value 保存的bitmap数据 */ public void put(Stringkey,Bitmap value) { put(key, Utils.Bitmap2Bytes(value)); } /** * 保存 bitmap 到 缓存中 * * @param key 保存的key * @param value 保存的 bitmap 数据 * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,Bitmap value, int saveTime) { put(key, Utils.Bitmap2Bytes(value), saveTime); } /** * 读取 bitmap 数据 * * @return bitmap 数据 */ public Bitmap getAsBitmap(Stringkey) { if (getAsBinary(key) == null) { return null; } return Utils.Bytes2Bimap(getAsBinary(key)); } // ======================================= // ============= drawable 数据 读写 ============= // ======================================= /** * 保存 drawable 到 缓存中 * * @param key 保存的key * @param value 保存的drawable数据 */ public void put(Stringkey,Drawable value) { put(key, Utils.drawable2Bitmap(value)); } /** * 保存 drawable 到 缓存中 * * @param key 保存的key * @param value 保存的 drawable 数据 * @param saveTime 保存的时间,单位:秒 */ public void put(Stringkey,Drawable value, int saveTime) { put(key, Utils.drawable2Bitmap(value), saveTime); } /** * 读取 Drawable 数据 * * @return Drawable 数据 */ public Drawable getAsDrawable(Stringkey) { if (getAsBinary(key) == null) { return null; } return Utils.bitmap2Drawable(Utils.Bytes2Bimap(getAsBinary(key))); } /** * 获取缓存文件 * * @return value 缓存的文件 */ public File file(Stringkey) { File f = mCache.newFile(key); if (f.exists())return f; return null; } /** * 移除某个key * * @return 是否移除成功 */ public boolean remove(Stringkey) { return mCache.remove(key); } /** * 清除所有数据 */ public void clear() { mCache.clear(); } * @title 缓存管理器 */ public class ACacheManager { private final AtomicLong cacheSize; private final AtomicInteger cacheCount; private final long sizeLimit; private final int countLimit; private final Map<File,Long> lastUsageDates=Collections.synchronizedMap(newHashMap<File,Long>()); protected File cacheDir; private ACacheManager(FilecacheDir,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(); } private void put(Filefile) { 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); } private File get(Stringkey) { File file = newFile(key); Long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); return file; } private File newFile(Stringkey) { return new File(cacheDir, key.hashCode()+""); } private boolean remove(Stringkey) { File image = get(key); return image.delete(); } private void clear() { lastUsageDates.clear(); cacheSize.set(0); File[] files = cacheDir.listFiles(); if (files != null) { for (File f: files) { f.delete(); } } } /** * 移除旧的文件 */ 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; } private long calculateSize(Filefile) { return file.length(); } } /** * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 * @title 时间计算工具类 */ private static class Utils { /** * 判断缓存的String数据是否到期 * * @return true:到期了 false:还没有到期 */ private static boolean isDue(String str) { return isDue(str.getBytes()); } /** * 判断缓存的byte数据是否到期 * * @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 String newStringWithDateInfo(intsecond,String strInfo) { return createDateInfo(second)+ strInfo; } private static byte[] newByteArrayWithDateInfo(intsecond,byte[] data2) { byte[] data1 = createDateInfo(second).getBytes(); byte[] retdata = new byte[data1.length + data2.length]; System.arraycopy(data1,0, retdata,0, data1.length); System.arraycopy(data2,0, retdata, data1.length, data2.length); return retdata; } private static String clearDateInfo(StringstrInfo) { if (strInfo != null && hasDateInfo(strInfo.getBytes())) { strInfo = strInfo.substring(strInfo.indexOf(mSeparator)+1, strInfo.length()); } return strInfo; } private static byte[] clearDateInfo(byte[]data) { if (hasDateInfo(data)) { return copyOfRange(data, indexOf(data, mSeparator)+1, data.length); } return data; } private static boolean hasDateInfo(byte[] data) { return data != null && data.length > 15 && data[13] == '-'&& indexOf(data, mSeparator)>14; } 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; } // private static int indexOf(byte[] data, char c) { for (int i=0; i < data.length; i++) { if (data[i] == c) { return i; } } return -1; } //时间上 private static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " >"+ to); byte[] copy = new byte[newLength]; System.arraycopy(original, from, copy,0,Math.min(original.length- from, newLength)); return copy; } private static final char mSeparator = ' '; private static String createDateInfo(int second) { String currentTime = System.currentTimeMillis()+""; while (currentTime.length()<13) { currentTime = "0"+ currentTime; } return currentTime + "-"+ second+ mSeparator; } /* * Bitmap → byte[] */ private static byte[] Bitmap2Bytes(Bitmapbm) { if (bm == null) { return null; } ByteArrayOutputStream baos=new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.PNG,100, baos); return baos.toByteArray(); } /*将byte数据转化为bitmap * byte[] → Bitmap */ private static Bitmap Bytes2Bimap(byte[] b) { if (b.length==0) { return null; } return BitmapFactory.decodeByteArray(b,0, b.length); } /* 把drawable转化为bitmap数据 * Drawable → Bitmap */ private static Bitmap drawable2Bitmap(Drawabledrawable) { if (drawable == null) { return null; } // 取 drawable 的长宽 int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); // 取 drawable 的颜色格式 Bitmap.Config config= drawable.getOpacity()!=PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 建立对应 bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); // 建立对应 bitmap 的画布 Canvas canvas = new Canvas(bitmap); drawable.setBounds(0,0, w, h); // 把 drawable 内容画到画布中 drawable.draw(canvas); return bitmap; } /* * Bitmap → Drawable */ @SuppressWarnings("deprecation")privatestatic Drawable bitmap2Drawable(Bitmapbm) { if (bm == null) { return null; } return new BitmapDrawable(bm); } } }使用Acache来缓存网络请求数据,可以使app端本地可以先缓存http的发送过来的数据内容,比如设置缓存时间是1个小时,可以让用户不用频繁的去刷新内容,频繁加载数据,使用户流量消耗较大,并且频繁请求数据会降低app的性能。 0 0
- Acache缓存的使用
- 15.缓存工具类ACache的使用
- Android开发----Acache缓存框架的使用
- 使用ACache缓存List类型的数据
- Acache使用过程的大坑
- 【FastDev4Android框架开发】Android 数据缓存器ACache的详解和使用(四)
- Okhttp和Picasso配合使用外加ACache实现缓存
- Android 使用sharedpreferences、ACache缓存用户名和密码
- Android 使用sharedpreferences、ACache缓存用户名和密码
- android本地缓存ACache
- Android缓存框架:ACache
- ACache缓存框架
- 缓存之 ACache
- ACache轻量级缓存框架
- android ACache 缓存
- android轻量级缓存框架ACache
- ASimpleCache (ACache)缓存框架
- ACache-缓存-一个轻量级框架
- Java并发容器和框架
- 剑指offer-- 反转链表
- 面试总结
- cmdline常用参数
- 两个例子(来自Storm实战 构建大数据实时计算)
- Acache缓存的使用
- Java8初体验(二)Stream语法详解
- springmvc三种处理器映射器handlerMapping
- 选择排序法的理解
- 03 函数参数的默认值
- 深入理解uwsgi和gunicorn网络模型
- Myeclipse搭建Maven环境
- html2canvas图片截图截屏功能,附demo地址
- Java8初体验(一)lambda表达式语法