SharedPreferences多進(jìn)程共享數(shù)據(jù)爬坑之旅

SharedPreferences ContentProvider Application


1. 遇到的問題

05-23 16:11:15.871: E/AndroidRuntime(21899): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.SharedPreferences android.content.Context.getSharedPreferences(java.lang.String, int)' on a null object reference
05-23 16:11:15.871: E/AndroidRuntime(21899): at com.csmijo.test.utils.SharedPrefUtil.getSharedPreferences(SharedPrefUtil.java:13)
05-23 16:11:15.871: E/AndroidRuntime(21899): at com.csmijo.test.utils.SharedPrefUtil.getValue(SharedPrefUtil.java:51)

寫好的一個 SDK 在第三方集成使用時(shí)祝沸,發(fā)現(xiàn)了這樣的bug哑芹。于是根據(jù) trace 信息,查看代碼發(fā)現(xiàn)封裝類在操作 SharedPreferences 時(shí)并沒有什么問題冠蒋,但是為什么會出現(xiàn) NullPointerException 的問題呢?梯浪?

于是溝通拿到測試 Apk 后,安裝發(fā)現(xiàn)是因?yàn)?第三方APP在打開某個Activity時(shí)啟動了新的進(jìn)程株依,所以導(dǎo)致了上述的問題驱证。

找到原因后,于是開始嘗試解決恋腕。抹锄。。

2. 通過 SharedPreferences 實(shí)現(xiàn)多進(jìn)程間的數(shù)據(jù)共享(不推薦)

因?yàn)橹暗臄?shù)據(jù)都是使用 SharedPreferences 進(jìn)行存儲,如果改用其他多進(jìn)程的通信方式感覺改動的地方比較大伙单,所以優(yōu)先嘗試使用修改 SharedPreferences 的方式進(jìn)行获高。

通過查看 API 文檔發(fā)現(xiàn),在 API Level > 11 即 Android 3.0 可以通過 Context.MODE_MULTI_PROCESS 屬性來實(shí)現(xiàn)多進(jìn)程間的數(shù)據(jù)共享.

但是在 API 23 時(shí)該屬性被廢棄吻育。官方文檔中明確寫明 This class does not support use across multiple processes.SharedPreferences 不適用于多進(jìn)程間共享數(shù)據(jù)念秧,推薦使用 ContentProvider

3. 更新(使用 ContentProvider 的一次嘗試 )

之前自己嘗試了一下使用 contentProvider + SharedPreferences 來實(shí)現(xiàn)布疼,沒有成功摊趾,還是水平太次啊。最近在逛掘金醬的時(shí)候發(fā)現(xiàn)很早之前就有人實(shí)現(xiàn)了這樣的方式游两,這里貼一下我找的的博客及代碼砾层,以防誤人子弟啊。

以下是我嘗試失敗的例子贱案,這里記錄一下肛炮。

3. 使用 ContentProvider 的一次嘗試 (失敗)

平時(shí)自定義 ContentProvider 時(shí)宝踪,都是和 Sqlite 配合使用侨糟,將數(shù)據(jù)存儲在數(shù)據(jù)庫中,于是突發(fā)奇想瘩燥,能不能把 ContentProviderSharedPreferences 聯(lián)合使用秕重,使用 SharedPreferences 來存儲數(shù)據(jù)。

于是直接上手鼓搗了半天颤芬,最后在自定義 ContentProviderquery() 方法面前敗下陣來悲幅。

這是因?yàn)?public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 方法需要返回一個 Cursor 的對象套鹅。查看代碼后發(fā)現(xiàn) Cursor 是一個接口站蝠,于是想著實(shí)現(xiàn)一個自定義的接口即可。

結(jié)果一陣敲碼完成之后卓鹿,run一下菱魔,結(jié)果呵呵了,提示如下的bug:

Caused by: java.lang.ClassCastException: android.content.ContentResolver$CursorWrapperInner cannot be cast to csmijo.com.test.MyCursor
at csmijo.com.test.SharedPrefUtil.getValue(SharedPrefUtil.java:78)

于是開始找原因吟孙,發(fā)現(xiàn)在使用ContentResolver.query() 方法時(shí)發(fā)生了如下的調(diào)用:

contentSolver_query.png

而正常情況下返回 ContentResolver$CursorWrapperInner 類的一個實(shí)例澜倦,而這個類是一個 private final class,所以沒有辦法繼承杰妓。該類的繼承結(jié)構(gòu)如下圖所示:

ContentResolver_query_cursor.png

所以我們直接實(shí)現(xiàn) Cursor 接口作為返回值的做法是錯誤的藻治。

4. 使用 ContentProvider 完成多進(jìn)程間數(shù)據(jù)共享

嘗試之后失敗,但是問題還是要解決的嘛巷挥,所以就乖乖使用 ContentProviderSqlite 的方案進(jìn)行問題解決桩卵。 具體的 ContentProvider 使用方法可以參考 官方教程

在調(diào)試 ContentProvider 的時(shí)候,使用了 Stetho雏节, 它可以在 Chrome 中非常方便的查看數(shù)據(jù)庫中的資源胜嗓,還支持 SQL 查詢,特別的方便钩乍,推薦一下辞州。

5. 多進(jìn)程 Application 的多次加載

通過上面的 ContentProvider 解決了 SharedPreferences 共享數(shù)據(jù)的問題,自己調(diào)試了一下寥粹,發(fā)現(xiàn) Application 的初始化又有個坑变过。

因?yàn)槭褂昧硕噙M(jìn)程,每個進(jìn)程相當(dāng)于一個單獨(dú)的應(yīng)用程序涝涤,所以每個進(jìn)程啟動時(shí)都會調(diào)用一次 Applicaiton.onCreate() 方法牵啦,這樣就導(dǎo)致了我在 onCreate() 方法中進(jìn)行的操作執(zhí)行多遍。

解決方案是根據(jù)進(jìn)程來分別進(jìn)行初始化妄痪。

獲取當(dāng)前運(yùn)行進(jìn)程的名稱:

方法一

public static String getProcessName(Context cxt, int pid) {  
    ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);  
    List<RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();  
    if (runningApps == null) {  
        return null;  
    }  
    for (RunningAppProcessInfo procInfo : runningApps) {  
        if (procInfo.pid == pid) {  
            return procInfo.processName;  
        }  
    }  
    return null;  
} 

這是目前網(wǎng)上主流的方法哈雏,但是沒有方法二效率高

方法二

public static String getCurrentProcessName() {
        FileInputStream in = null;
        try {
            String fn = "/proc/self/cmdline";
            in = new FileInputStream(fn);
            byte[] buffer = new byte[256];
            int len = 0;
            int b;
            while ((b = in.read()) > 0 && len < buffer.length) {
                buffer[len++] = (byte) b;
            }
            if (len > 0) {
                return new String(buffer, 0, len, "UTF-8");
            }
        } catch (Throwable e) {
        } finally {

            try {
                if (null != in) {
                    in.close();
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return null;
    }

6. 總結(jié)

以上就是這次多進(jìn)程數(shù)據(jù)共享爬坑的過程,希望能夠提供一些借鑒作用衫生。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裳瘪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子罪针,更是在濱河造成了極大的恐慌彭羹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泪酱,死亡現(xiàn)場離奇詭異派殷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)墓阀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門毡惜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人斯撮,你說我怎么就攤上這事经伙。” “怎么了勿锅?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵帕膜,是天一觀的道長。 經(jīng)常有香客問我溢十,道長垮刹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任张弛,我火速辦了婚禮荒典,結(jié)果婚禮上宗挥,老公的妹妹穿的比我還像新娘。我一直安慰自己种蝶,他們只是感情好契耿,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著螃征,像睡著了一般搪桂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盯滚,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天踢械,我揣著相機(jī)與錄音,去河邊找鬼魄藕。 笑死内列,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的背率。 我是一名探鬼主播话瞧,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼寝姿!你這毒婦竟也來了交排?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤饵筑,失蹤者是張志新(化名)和其女友劉穎埃篓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體根资,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡架专,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玄帕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片部脚。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖桨仿,靈堂內(nèi)的尸體忽然破棺而出睛低,到底是詐尸還是另有隱情,我是刑警寧澤服傍,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站骂铁,受9級特大地震影響吹零,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拉庵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一灿椅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦茫蛹、人聲如沸操刀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骨坑。三九已至,卻和暖如春柬采,著一層夾襖步出監(jiān)牢的瞬間欢唾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工粉捻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留礁遣,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓肩刃,卻偏偏與公主長得像祟霍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子盈包,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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

  • 一.菜單Menu 1.OptionsMenu 選項(xiàng)菜單 也叫系統(tǒng)菜單,右上角的三點(diǎn) (1)高版本的菜單 ...
    chaohx閱讀 985評論 0 7
  • 2017年5月17日 Kylin_Wu 標(biāo)注(★☆)為考綱明確給出考點(diǎn)(必考) 常見手機(jī)系統(tǒng)(★☆) And...
    Azur_wxj閱讀 1,801評論 0 10
  • 前幾天整理了Java面試題集合,今天再來整理下Android相關(guān)的面試題集合.如果你希望能得到最新的消息,可以關(guān)注...
    Boyko閱讀 3,621評論 8 135
  • 我知道我是個感性的人续语,是個性情中人垂谢,是個一直保持元?dú)饧冋娴倪^活的人,所以我容易被感動容易大笑容易流淚疮茄,情緒波動起伏...
    讀娘閱讀 641評論 0 0
  • 大雨后 城市是綠色的 天空有座虹橋 葉子沒了塵土 花瓣多了淚珠 淚水中 世界是灰色的 你的身影還在 而你卻已遠(yuǎn)去 ...
    梔子枝z閱讀 178評論 0 5