1、SharedPreferences不支持多進(jìn)程
Android的SharedPreferences用來存儲一些鍵值對, 但是卻不支持跨進(jìn)程使用.跨進(jìn)程來用的話, 當(dāng)然是放在數(shù)據(jù)庫更可靠.
SharedPreferences不支持多進(jìn)程
SharedPreferences對多進(jìn)程的支持不好, 你用什么mode也沒用, 所以官方已經(jīng)廢棄了原先的MODE_MULTI_PROCESS, 并且建議跨進(jìn)程存取值還是用ContentProvider之類的更靠譜一些.說明見:Context#MODE_MULTI_PROCESS
2润樱、通過ContentProvider進(jìn)行實(shí)現(xiàn)多進(jìn)程共享SharedPreferences
既然SP有多進(jìn)程不同步的隱患,那么我們怎么要怎么解決呢纷妆? 多進(jìn)程同步的方法中饲窿,ContentProvider、Messenger易茬、AIDL等方式都是基于Binder實(shí)現(xiàn)的茧妒,所以本質(zhì)上并沒有太大差別萧吠,而ContentProvider又是Android提倡的數(shù)據(jù)提供組件,所以我選擇它來實(shí)現(xiàn)多進(jìn)程SP操作桐筏。
SP本身的調(diào)用方式已經(jīng)提供了較高的存取便利性纸型,所以我們只要封裝出一個SPHelper,去調(diào)用SPContentProvider梅忌,SPContentProvider用于保證跨進(jìn)程的同步性狰腌,其內(nèi)部再用SPHelperImpl來做真正的實(shí)現(xiàn)即可。
SP本身的調(diào)用方式已經(jīng)提供了較高的存取便利性牧氮,所以我們只要封裝出一個SPHelper琼腔,去調(diào)用SPContentProvider,SPContentProvider用于保證跨進(jìn)程的同步性蹋笼,其內(nèi)部再用SPHelperImpl來做真正的實(shí)現(xiàn)即可展姐。
那怎么用SPContentProvider來實(shí)現(xiàn)數(shù)據(jù)存取操作呢躁垛?實(shí)現(xiàn)ContentProvider需要實(shí)現(xiàn)幾個方法剖毯,這些方法分別對應(yīng)了ContentResolver中的同名方法,我們可以通過ContentResolver來調(diào)用這些方法教馆,達(dá)到傳遞數(shù)據(jù)和進(jìn)行命令解析的目的逊谋。
SP中的方法有sava,get土铺,remove胶滋,clean板鬓,getAll這幾種。那么我們可以用update或insert來實(shí)現(xiàn)save究恤;用delete實(shí)現(xiàn)clean和remove俭令,用getType或者query實(shí)現(xiàn)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) {
// 用這個來取數(shù)值
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);
}
...
}
優(yōu)化性能和內(nèi)存 本來以為做完上面的工作就算完了部宿,但是在實(shí)際使用的過程中抄腔,發(fā)現(xiàn)一個問題,就是內(nèi)存消耗比較大理张。tracking后發(fā)現(xiàn)是由于生成的SharedPreferences.Editor對象占用了大量內(nèi)存赫蛇,這是因?yàn)槲业膽?yīng)用場景中,會頻繁的將運(yùn)行過程中的幾個數(shù)據(jù)存儲到SP中雾叭,所以導(dǎo)致大量生成Editor對象悟耘。但是實(shí)際上,很多保存的值是相同的织狐,此時可以考慮使用緩存機(jī)制暂幼,而不用重復(fù)寫入,代碼如下:
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);
}