Android開發藝術探索知識回顧——第2章 IPC機制:2、不同的 IPC 方式

2.4 Android 中的 IPC 方式

在上節中,我們介紹了 IPC 的幾個基礎知識:序列化和 Binder,本節開始詳細分析各種跨進程通信方式。具體方式有很多,比如可以通過在 Intent 中附加 extras 來傳遞信息,或者通過共享文件的方式來共享數據,還可以採用 Binder 方式來跨進程通信,

另外, Contentprovider 天生就是支持跨進程訪問的,因此我們也可以釆用它來進行 IPC此外,通過網絡通信也是可以實現數據傳遞的,所以 Socket 也可以實現 IPC上述所說的各種方法都能實現 IPC,它們在使用方法和側重點上都有很大的區別,下面會一一進行展開。

2.4.1 使用 Bundle

我們知道,四大組件中的三大組件(ActivityService、Receiver)都是支持在 Intent 中傳遞 Bundle 數據的,由於 Bundle 實現了 Parcelable 接口,所以它可以方便地在不同的進程間傳輸。基於這一點,當我們在一個進程中啓動了另一個進程的 Activity。Service 和 Receiver,我們就可以在 Bundle 中附加我們需要傳輸給遠程進程的信息,並通過Intent發送出去。

當然,我們傳輸的數據必須能夠被序列化,比如基本類型、實現了  Parcellable  接口的對象、實現了 Serializable 接口的對象以及 些 Android 支持的特殊對象,具體內容可以看 Bundle 這個類,就可以看到所有它支持的類型。Bundle 不支持的類型我們無法通過它在進程間傳遞數據,這個很簡單,就不再詳細介紹了。這是一種最簡單的進程間通信方式,

除了直接傳遞數據這種典型的使用場景,它還有一種特殊的使用場景。比如 進程正在進行一個計算,計算完成後它要啓動 進程的一個組件並把計算結果傳遞給 進程,可是遺憾的是這個計算結果不支持放入 Bundle 中,因此無法通過 Intent 來傳輸,這個時候如果我們用其他 IPC 方式就會略顯複雜。可以考慮如下方式:我們通過 Intent 啓動進程 的一個 Service 組件(比如IntentService)。讓 Service 在後臺進行計算,計算完畢後再啓動 B 進程中真正要啓動的目標組件,由於 Service 也運行在 進程中,所以目標組件就可以直接獲取計算結果,這樣一來就輕鬆解決了跨進程的問題。這種方式的核心思想在於將原本需要在 進程的計算任務轉移到 進程的後臺 Service 中去執行,這樣就成功地避免了進程間通信問題,而且只用了很小的代價。

2.4.2 使用文件共享

共享文件也是一種不錯的進程間通信方式,兩個進程通過讀/寫同一個文件來交換數據,比如 進程把數據寫入文件,進程通過讀取這個文件來獲取數據。我們知道,在 Windows上,一個文件如果被加了排斥鎖將會導致其他線程無法對其進行訪問,包括讀和寫,而由於Android 系統基於 Linux,使得其併發讀/寫文件可以沒有限制地進行,甚至兩個線程同時對同一個文件進行寫操作都是允許的,儘管這可能出問題。通過文件交換數據很好使用,除了可以交換一些文本信息外,我們還可以序列化一個對象到文件系統中的同時,從另一個進程中恢復這個對象,下面就展示這種使用方法。

還是本章剛開始的那個例子,這次我們在 MainActivity 的 onResume 中序列化一個 User 對象到 sd 卡上的一個文件裏,然後在SecondActivity 的 onResume 中去反序列化,我們期望在 SecondActivity 中能夠正確地恢復User對象的值。關鍵代碼如下:

 

下面看一下log,很顯然,在 SecondActivity 中成功地從文件從恢復了之前存儲的 User 對象的內容,這裏之所以說內容,是因爲反序列化得到的對象只是在內容上和序列化之前的對象是一樣的,但它們本質上還是兩個對象。

通過文件共享這種方式來共享數據對文件格式是沒有具體要求的,比如可以是文本文 件,也可以是XML文件,只要讀/寫雙方約定數據格式即可。通過文件共享的方式也是有侷限性的,比如併發讀/寫的問題,像上面的那個例子,如果併發讀/寫,那麼我們讀出的內容就有可能不是最新的,如果是併發寫的話那就更嚴重了。

因此我們要儘量避免併發寫這種情況的發生,或者考慮使用線程同步來限制多個線程的寫操作。通過上面的分析,我們可以知道,文件共享方式,適合在對數據同步要求不高的,進程之間進行通信,並且要妥善處理併發讀/寫的問題。

當然,SharedPreferences是個特例,衆所周知,SharedPreferences 是 Android 中提供的輕量級存儲方案,它通過鍵值對的方式來存儲數據,在底層實現上它採用 XML 文件來存儲鍵值對,每個應用的 SharedPreferences 文件都可以在當前包所在的 data 目錄下査看到。—般來說,它的目錄位於 /data/data/package name/shared_prefs 目錄下,其中 package name 表示的是當前應用的包名。

從本質上來說,SharedPreferences 也屬於文件的一種,但是由於系統對它的讀/寫有一定的緩存策略,即在內存中會有一份SharedPreferences 文件的緩存,因此在多進程模式下,系統對它的讀/寫就變得不可靠,當面對高併發的讀/寫訪問,Sharedpreferences有很大機率會丟失數據,因此,不建議在進程間通信中使用 SharedPreferences

 

2.4.3 使用 Messenger

Messenger 可以翻譯爲信使,顧名思義,通過它可以在不同進程中傳遞 Message 對象, 在Message中放入我們需要傳遞的數據,就可以輕鬆地實現數據的進程間傳遞了。Messenger 是一種輕量級的 IPC 方案,它的底層實現是AIDL,爲什麼這麼說呢,我們大致看一下 Messenger 這個類的構造方法就明白了。下面是 Messenger 的兩個構造方法,從構造方法的實現上我們可以明顯看出 AIDL 的痕跡,不管是 IMessenger 還是 Stub.aslnterface,這種使用方法都表明它的底層是 AIDL。

 

Messenger 的使用方法很簡單,它對 AIDL 做了封裝,使得我們可以更簡便地進行進程間通信。同時,由於它一次處理一個請求,因此在服務端我們不用考慮線程同步的問題,這是因爲服務端中不存在併發執行的情形。實現一個 Messenger 有如下幾個步驟,分爲服務端和客戶端。

 

整理中。。。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章