android 利用lru算法实现SharedPreferences的二级缓存

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

}
当然,有了这个思路后,我们也可以对数据库中常用的数据进行内存缓存,以减小数据库访问的压力。
                                                             
 
 

猜你喜欢

转载自blog.csdn.net/Panda_Kill/article/details/79899114