1. 程式人生 > >Android IPC簡介之(多程序模式)初識

Android IPC簡介之(多程序模式)初識

前言

IPC是 Inter-Process Communication 的縮寫,含義為 程序間通訊 或者跨程序通訊,是指兩個程序之間進行資料交換的過程。

執行緒vs程序

執行緒

執行緒是CPU排程的最小單元,同時執行緒是一種有限的系統資源。

程序

程序一般指一個執行單元,在 PC 和移動裝置上通常指一個程式或者一個應用。

程式、程序、執行緒關係

通常來講,一個程式就是一個程序(開啟了多程序的程式除外),一個程序可以包含多個執行緒,當然一個程序也可以只有一個執行緒(畢竟人家就喜歡所有操作都放一個執行緒執行嘛,然後來個 ANR 就爽了),即主執行緒,在 Android 中我們常稱之為 UI 執行緒,只有在 UI 執行緒中才能操作介面元素。

這裡寫圖片描述

關係圖(借用)

Android 中的多程序模式

Android是基於Linux的作業系統,它有自己的程序間通訊方式,Android 通過 Binder 可以輕鬆的實現程序間通訊,當然也可以通過 Socket 來實現任意兩個終端之間的通訊(這裡暫不詳細介紹)。

為什麼要程序間通訊

  • 應用自身原因需要採用多程序模式來實現(例如:某些工具類 APP 的系統清理需要執行在單獨的程序中)
  • 某些操作對記憶體要求較高,通過開啟多程序來獲取多份記憶體空間(Android 對單個應用所使用的最大記憶體做了限制)
  • 一個應用需要向另一個應用獲取所需資料,兩個應用需要跨程序通訊(ContentProvider 就是跨程序通訊,通訊細節被系統內部遮蔽)

如何開啟多程序

在 Android 中使用多程序只有一種方法就是給四大元件(Activity、Service、BroadcastReceiver、ContentProvider)在 AndroidManifest.xml 中指定 android:process 屬性,注意:無法為一個執行緒或者一個實體類去指定執行時所在的執行緒。

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".SecondActivity" android:process=":remote"/> <activity android:name=".ThirdActivity" android:process="com.wiwide.processdemo.remote"/>
命名方式 示例 類別 特點
“:”開頭 “:remote” 當前應用私有程序 其他應用的元件不可以與它跑在同一程序中
完整命名 “com.wiwide.processdemo.remote” 全域性程序 其他應用可以通過 SharedUID 與它跑在同一程序中


我們知道 Android 系統會為每個應用分配一個唯一的 UID,具有相同 UID 的應用才能共享資料。兩個應用通過 ShareUID 跑在同一個程序中是有要求的,需要兩個應用有 相同的 ShareUID 還得 簽名相同 才可以。(>>ShareUID 傳送門<<)
如果兩個應用滿足了相同的 ShareUID 和相同的簽名,那麼他們就已經可以互相訪問對方的私有資料了,例如 data 目錄,元件資訊等,不管它們是否跑在同一個程序中。當然,如果這兩個應用還跑在了同一個程序中,那麼除了可以共享 data 目錄和元件資訊外,還可以共享記憶體資料了,這時候這兩個應用可以看做是一個應用中的兩個部分了,是不是很神奇!

多程序引發的問題

Android 為每一個應用分配了一個獨立的虛擬機器,或者說為每個程序分配一個獨立的虛擬機器,不同的虛擬機器在記憶體分配上有不同的地址空間,在不同的虛擬機器中訪問同一個類的物件會產生多份副本。

  • 靜態成員和單例模式完全失效
  • 執行緒同步機制完全失效
  • SharedPreferences 的可靠性下降
  • Application 會被多次建立

靜態成員和單例模式、執行緒同步機制完全失效

新建一個類 UserManager,定義一個 public 的靜態成員變數 sUserId = 1,在 MainActivity 的 onCreate 方法中列印這個值,然後修改為 sUserId = 2 之後再次列印,修改成功。開啟 SecondActivity (執行在另一個程序中)時同樣在 onCreate 方法中再次列印下 sUserId,結果你會驚奇的發現,怎麼還是 1 嘞。。

這裡寫圖片描述


在 MainActivity 所在的程序 com.wiwide.processdemo 和 SecondActivity 所在的程序 com.wiwide.processdemo:remote 中,它們執行在不同的虛擬機器中,也就在不同的記憶體空間中都有一個 UserManager 類,並且這兩個類互不干擾,在一個程序中修改 sUserId 的值之後影響當前程序,對其他程序不會造成任何影響。既然都不在同一塊記憶體了,那麼單例模式和所謂的執行緒同步需要用到的鎖物件或者鎖全域性類都已經不是同一個物件了。

SharedPreferences 的可靠性下降

SharedPreferences 不支援多個程序同時去執行寫操作,否則會導致一定機率的資料丟失,這是因為 SharedPreferences 底層是通過讀寫 xml 檔案來實現的,併發寫顯然可能出現問題,甚至併發讀/寫都可能出問題。

Application 會被多次建立

當一個元件跑在一個新的程序中的時候,由於系統要在建立新的程序的同時分配獨立的虛擬機器,所以這個過程其實就是啟動一個應用的過程。因此,相當於系統又把這個應用重新啟動了一邊,既然重新啟動了,那麼自然會建立新的 Application 。即:每個程序都有屬於自己的虛擬機器和 Application

這裡寫圖片描述


通過 log 可以發現 Application 確實執行了三次 onCreate,並且每次的程序名和程序 id 都不一樣。

注意:

筆者剛開始是通過 Android Studio 除錯的,結果一直無法打印出來三次啟動的 log(搞得我都懷疑是不是我寫的程式碼有問題了),後來無奈換到了 DDMS 上成功列印了,才忽然反應過來 Studio 中的 logcat 預設是選擇當前的程序,然而我們開啟第二個 Activity 時開啟了一個新的程序,這會的 log 當然不會在這裡列印了。只需要把程序切換到 System 就可以了,當然 log 比較多,建議過濾一下。

本文參考了《Android 開發藝術探索》的相關章節,關於 IPC 中的多程序知識就先介紹到此,更多深入內容隨後再做探討。如果在閱讀中發現哪裡有難以理解或者描述不當的地方,歡迎留言指出!謝謝!