LRU算法 : last recent uesed 最近最少使用原则的算法,androidSDK中提供的lrucache类其实是维护一个map, 对map中的数据进行增删,来达到内存缓存的目的。
应用场景:
一般我们开发时会有一些数据会存在SharedPreferences中,比如用户的基本信息,服务器的token等,这些信息用的比较频繁,每次要取这些值的时候都要从SharedPreferences对象中去取,其实呢,SharedPreferences对象是对本地存的xml进行解析,读到你存的key值的时候取出其中的value返回回来,我们才得到了SharedPreferences中存的值,但是呢,这个过程是有读文件和解析xml的过程,有一定的时间消耗。有的开发者干脆就在app启动的时候就把那些常用的数据读到内存中,方便使用,这就造成了内存泄露的问题。所以我就利用Lru缓存机制对SharedPreferences中的数据进行了缓存处理,以解决读取慢和内存泄露问题。
废话不多少,直接上代码。
1,首先写一个接口定义内存缓存要做的事情,主要就是存和取。
public interface MeMoryCache { void put(String key , String value); String getString(String key); }
2,写一个类实现上面的接口,主要是对缓存区的数据进行存取操作,详情看注释:
public class MeMaryCacheImpl implements MeMoryCache { private LruCache<String, String> lruCache; private static MeMaryCacheImpl mInstance; public static MeMaryCacheImpl getInstance(){ if(mInstance == null){ synchronized (MeMaryCacheImpl.class){ if (mInstance == null){ mInstance = new MeMaryCacheImpl(); } } } return mInstance; } private MeMaryCacheImpl(){ init(); } /** * 初始化lruCache */ private void init() { //获取系统分配给当前应用的最大内存 int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); //取其中的1/16大小作为缓存区来缓存数据 int cacheSize = maxMemory/16; lruCache = new LruCache<String,String>(cacheSize){ @Override protected int sizeOf(String key, String value) { //重写sizeOf 方法,来进行缓存的数据的大小计算,算法内部会根据该方法的返回值进行内存分配, //如果放到缓存区中的内存占用超过 cacheSize ,就会删除不最近最少使用的数据 return value.length()/1024; } }; } /** * 往缓存区存数据 */ @Override public void put(String key, String value) { if (TextUtils.isEmpty(key)||TextUtils.isEmpty(value)){ LogUtils.e("can't put null to cache because key or value is null"); return; } lruCache.put(key, value); } /** * 取缓存区的数据 */ @Override public String getString(String key) { if (TextUtils.isEmpty(key)){ LogUtils.e("can't get value because key is null"); return null; } return lruCache.get(key); } /** * 清楚缓存区数据 */ public void clearCache(){ lruCache.evictAll(); } }3,写一个工具类,将SharedPreferences操作和缓存机制联系起来。主要思路就是:在往sp中存数据的时候也在缓存区中存一份,在取sp中的数据时,先从缓存区中取,取到了就直接用缓存区中的内容,没有取到再去sp中取,从sp中取到后再放一次缓存区,方便下次取用
public class CacheUtils { private static final String SP_TEST = "SP_TEST"; /** * 存缓存和sp字符串值 */ public static void putString(Context context, String key, String value) { SharedPreferences sp = context.getSharedPreferences(SP_TEST, 0); SharedPreferences.Editor editor = sp.edit(); editor.putString(key, value); MeMaryCacheImpl.getInstance().put(key, value); editor.commit(); } /** * 取缓存或sp字符串值 */ public static String getString(Context context, String key) { if (TextUtils.isEmpty(key)) { LogUtils.e("can't get value because key is empty"); return null; } String value; value = MeMaryCacheImpl.getInstance().getString(key); if (TextUtils.isEmpty(value)) { SharedPreferences sp = context.getSharedPreferences(SP_TEST, 0); String string = sp.getString(key, ""); if (TextUtils.isEmpty(string)) { } else { LogUtils.i("get value from sp and put to cache"); MeMaryCacheImpl.getInstance().put(key, string); } return string; } else { LogUtils.i("get value from lru " + value); return value; } } /** * 存sp和缓存 int值 */ public static void putInt(Context context,String key ,int value){ SharedPreferences sp = context.getSharedPreferences(SP_TEST, 0); SharedPreferences.Editor editor = sp.edit(); editor.putInt(key, value); MeMaryCacheImpl.getInstance().put(key, String.valueOf(value)); editor.commit(); } /** * 取缓存或者sp的int值 */ public static int getInt(Context context,String key){ if (TextUtils.isEmpty(key)) { LogUtils.e("can't get value because key is empty"); return 0; } int value; String valueStr = MeMaryCacheImpl.getInstance().getString(key); if (TextUtils.isEmpty(valueStr)){ SharedPreferences sp = context.getSharedPreferences(SP_TEST,0); value = sp.getInt(key,0); MeMaryCacheImpl.getInstance().put(key,String.valueOf(value)); return value; }else { value = Integer.parseInt(valueStr); return value; } } /** * 存缓存和sp 布尔值 */ public static void putBoolean(Context context,String key,boolean value){ SharedPreferences sp = context.getSharedPreferences(SP_TEST,0); SharedPreferences.Editor edit = sp.edit(); edit.putBoolean(key,value); MeMaryCacheImpl.getInstance().put(key,String.valueOf(value)); edit.commit(); } /** * 取缓存或者sp 布尔值 */ public static boolean getBoolean(Context context , String key){ if (TextUtils.isEmpty(key)) { LogUtils.e("can't get value because key is empty"); return false; } String string = MeMaryCacheImpl.getInstance().getString(key); if (TextUtils.isEmpty(string)){ SharedPreferences sp = context.getSharedPreferences(SP_TEST,0); boolean value = sp.getBoolean(key, false); MeMaryCacheImpl.getInstance().put(key,String.valueOf(value)); return value; }else { return Boolean.parseBoolean(string); } } public static void clearCache(){ MeMaryCacheImpl.getInstance().clearCache(); LogUtils.i("clear cache"); } }
当然,有了这个思路后,我们也可以对数据库中常用的数据进行内存缓存,以减小数据库访问的压力。