通過ContentProvider實(shí)現(xiàn)SharedPreferences進(jìn)程共享數(shù)據(jù)

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

66093f3bcac9420c865dc1170dd616a2.png

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)即可展姐。

e48512dc45e02c473de634f9279f0ddc.png

那怎么用SPContentProvider來實(shí)現(xiàn)數(shù)據(jù)存取操作呢躁垛?實(shí)現(xiàn)ContentProvider需要實(shí)現(xiàn)幾個方法剖毯,這些方法分別對應(yīng)了ContentResolver中的同名方法,我們可以通過ContentResolver來調(diào)用這些方法教馆,達(dá)到傳遞數(shù)據(jù)和進(jìn)行命令解析的目的逊谋。

a099cf22a11332a32b7cc5c06194c7d0.png

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);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赚瘦,一起剝皮案震驚了整個濱河市粟誓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌起意,老刑警劉巖鹰服,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揽咕,居然都是意外死亡悲酷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門亲善,熙熙樓的掌柜王于貴愁眉苦臉地迎上來设易,“玉大人,你說我怎么就攤上這事蛹头《俜危” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵渣蜗,是天一觀的道長屠尊。 經(jīng)常有香客問我,道長耕拷,這世上最難降的妖魔是什么讼昆? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮骚烧,結(jié)果婚禮上浸赫,老公的妹妹穿的比我還像新娘闰围。我一直安慰自己,他們只是感情好既峡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布羡榴。 她就那樣靜靜地躺著,像睡著了一般运敢。 火紅的嫁衣襯著肌膚如雪炕矮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天者冤,我揣著相機(jī)與錄音肤视,去河邊找鬼。 笑死涉枫,一個胖子當(dāng)著我的面吹牛邢滑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播愿汰,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼困后,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衬廷?” 一聲冷哼從身側(cè)響起摇予,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吗跋,沒想到半個月后侧戴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡跌宛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年酗宋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疆拘。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜕猫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哎迄,到底是詐尸還是另有隱情回右,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布漱挚,位于F島的核電站翔烁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏棱烂。R本人自食惡果不足惜租漂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一阶女、第九天 我趴在偏房一處隱蔽的房頂上張望颊糜。 院中可真熱鬧哩治,春花似錦、人聲如沸衬鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸟赫。三九已至蒜胖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間抛蚤,已是汗流浹背台谢。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岁经,地道東北人朋沮。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像缀壤,于是被迫代替她去往敵國和親樊拓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容