面试

通过ContentProvider实现SharedPrefere

2017-08-20  本文已影响0人  king龙123

1、SharedPreferences不支持多进程

Android的SharedPreferences用来存储一些键值对, 但是却不支持跨进程使用.跨进程来用的话, 当然是放在数据库更可靠.
SharedPreferences不支持多进程
SharedPreferences对多进程的支持不好, 你用什么mode也没用, 所以官方已经废弃了原先的MODE_MULTI_PROCESS, 并且建议跨进程存取值还是用ContentProvider之类的更靠谱一些.说明见:Context#MODE_MULTI_PROCESS

66093f3bcac9420c865dc1170dd616a2.png

2、通过ContentProvider进行实现多进程共享SharedPreferences

既然SP有多进程不同步的隐患,那么我们怎么要怎么解决呢? 多进程同步的方法中,ContentProvider、Messenger、AIDL等方式都是基于Binder实现的,所以本质上并没有太大差别,而ContentProvider又是Android提倡的数据提供组件,所以我选择它来实现多进程SP操作。

SP本身的调用方式已经提供了较高的存取便利性,所以我们只要封装出一个SPHelper,去调用SPContentProvider,SPContentProvider用于保证跨进程的同步性,其内部再用SPHelperImpl来做真正的实现即可。

SP本身的调用方式已经提供了较高的存取便利性,所以我们只要封装出一个SPHelper,去调用SPContentProvider,SPContentProvider用于保证跨进程的同步性,其内部再用SPHelperImpl来做真正的实现即可。

e48512dc45e02c473de634f9279f0ddc.png

那怎么用SPContentProvider来实现数据存取操作呢?实现ContentProvider需要实现几个方法,这些方法分别对应了ContentResolver中的同名方法,我们可以通过ContentResolver来调用这些方法,达到传递数据和进行命令解析的目的。

a099cf22a11332a32b7cc5c06194c7d0.png

SP中的方法有sava,get,remove,clean,getAll这几种。那么我们可以用update或insert来实现save;用delete实现clean和remove,用getType或者query实现get和getAll。

public class SPHelper {
    ...

    public static final String CONTENT="content://";
    public static final String AUTHORITY="com.pl.sphelper";
    public static final String SEPARATOR= "/";
    public static final String CONTENT_URI =CONTENT+AUTHORITY;
    public static final String TYPE_INT="int";
    public static final String NULL_STRING= "null";

    public static int getInt(String name, int defaultValue) {
        ContentResolver cr = context.getContentResolver();
        Uri uri = Uri.parse(CONTENT_URI + SEPARATOR + TYPE_INT + SEPARATOR + name);
        String rtn = cr.getType(uri);
        if (rtn == null || rtn.equals(NULL_STRING)) {
            return defaultValue;
        }
        return Integer.parseInt(rtn);
    }
    ...
}

public class SPContentProvider extends ContentProvider{
    ...
    public static final String SEPARATOR= "/";

    public String getType(Uri uri) {
        // 用这个来取数值
        String[] path= uri.getPath().split(SEPARATOR);
        String type=path[1];
        String key=path[2];
        return  ""+SPHelperImpl.get(getContext(),key,type);
    }
    ...
}

class SPHelperImpl {
    ...

    public static final String TYPE_INT="int";

    static String get(Context context, String name, String type) {
        if (type.equalsIgnoreCase(TYPE_STRING)) {
            return getString(context, name, null);
        } else if (type.equalsIgnoreCase(TYPE_BOOLEAN)) {
            return getBoolean(context, name, false);
        } else if (type.equalsIgnoreCase(TYPE_INT)) {
            return getInt(context, name, 0);
        } else if (type.equalsIgnoreCase(TYPE_LONG)) {
            return getLong(context, name, 0L);
        } else if (type.equalsIgnoreCase(TYPE_FLOAT)) {
            return getFloat(context, name, 0f);
        } else if (type.equalsIgnoreCase(TYPE_STRING_SET)) {
            return getString(context, name, null);
        }
        return null;
    }

    static int getInt(Context context, String name, int defaultValue) {
        SharedPreferences sp = getSP(context);
        if (sp == null) return defaultValue;
        return sp.getInt(name, defaultValue);
    }
    ...
}

优化性能和内存 本来以为做完上面的工作就算完了,但是在实际使用的过程中,发现一个问题,就是内存消耗比较大。tracking后发现是由于生成的SharedPreferences.Editor对象占用了大量内存,这是因为我的应用场景中,会频繁的将运行过程中的几个数据存储到SP中,所以导致大量生成Editor对象。但是实际上,很多保存的值是相同的,此时可以考虑使用缓存机制,而不用重复写入,代码如下:

private static SoftReference<Map<String, Object>> sCacheMap;

private static Object getCachedValue(String name) {
    if (sCacheMap != null) {
        Map<String, Object> map = sCacheMap.get();
        if (map != null) {
            return map.get(name);
        }
    }
    return null;
}

private static void setValueToCached(String name, Object value) {
    Map<String, Object> map;
    if (sCacheMap == null) {
        map = new HashMap<>();
        sCacheMap = new SoftReference<Map<String, Object>>(map);
    } else {
        map = sCacheMap.get();
        if (map == null) {
            map = new HashMap<>();
            sCacheMap = new SoftReference<Map<String, Object>>(map);
        }
    }
    map.put(name, value);
}
synchronized static <T> void save(Context context, String name, T t) {
    SharedPreferences sp = getSP(context);
    if (sp == null) return;

    if (t.equals(getCachedValue(name))) {
        return;
    }
    SharedPreferences.Editor editor = sp.edit();
    if (t instanceof Boolean) {
        editor.putBoolean(name, (Boolean) t);
    }
    if (t instanceof String) {
        editor.putString(name, (String) t);
    }
    if (t instanceof Integer) {
        editor.putInt(name, (Integer) t);
    }
    if (t instanceof Long) {
        editor.putLong(name, (Long) t);
    }
    if (t instanceof Float) {
        editor.putFloat(name, (Float) t);
    }
    editor.commit();
    setValueToCached(name, t);
}
上一篇下一篇

猜你喜欢

热点阅读