一、Android中的多進程模式
1、Android中多進程是指一個應用中存在多個進程的情況,因此這裏不討論兩個應用之間的情況,首先在Android中使用多進程只有一種方法,那就是給四大組件指定android:process。 默認進程名是包名。
<activity
android:name=".MainActivity"
android:configChanges="orientation|screenSize"
android:launchMode="standard">
<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.liuguilin.multiprocesssample.remote" />
上面示例分別爲SecondActivity和ThirdActivity指定了process屬性,並且屬性值不同,當SecondActivity啓動時,系統會爲它創建一個單獨的進程,進程名爲con.liuguilin.multiprocesssample:remote;當ThridActivity啓動的時候,系統也會爲他創建一個單獨的進程,進程名com.liuguilin.multiprocesssample.remote,同時,入口Activity是MainActivity,沒有爲他指定process屬性,那麼他運行在默認進程中,當我們運行的時候就可以看到,進程列表末尾存在三個進程。查看進程方法如下:
C:\Users\hWX393093>adb shell ps | find "hfy"
u0_a128 27860 501 2278864 81132 0 0000000000 S demo.hfy.com.viewtest
SecondActivity和ThirdActivity的進程名分別爲“:remote”和包名.remote,區別在兩面:
a、”:“的含義,是指在當前的進程名前附加上包名,這是一種簡寫的方法,對於SecondActivity來說,他完整的進程名 爲 com.liuguilin.multiprocesssample:remote,而對於ThirdActivity中的申明方式,它是一種完整的命名方式,不會附加包名信息;
b、進程以”:“開頭的屬於當前應用的私有進程,其他應用的組件不可以和它跑在同一個進程中,而進程名不以”:“開頭的進程屬於全局進程,其他應用通過ShareUID方式可以和它跑在同一進程中。
一般使用私有進程。即“:”的形式。
2、Android爲每個進程都分配一個獨立的虛擬機,不同的虛擬機在內存上有不同的地址空間,這導致在不同的虛擬機中訪問同一個類的對象會產生多份副本,就我們這個例子來說,在兩個進程中都存在一個UserManager類,並且這兩個類是互不干擾的,在一個進程中修改mUseld的值只會影響當前進程,對其他進程不會造成任何影響,這樣我們就可以理解爲什麼在MainActivitv中修改了mUserld的值,但是在 SecondActivity 中這個值卻 沒有發生改變這個現象。
所有運行在不同進程中的四大組件,只要它們之間需要通過內存來共享數據,都會共享失敗這也是多進程帶來的主要影響,正常情況下四大組件中間不可能不通過一些中間層來共享數據,那麼通過簡單地指定進程名來開啓多進程都會無法正確運行。
一般來說,使用多進程會造成如下幾方面的問題:
b.線程同步機制完全失效。 ----因爲不是同一塊內存,即鎖對象不是同一個。
c.SharedPreferences的可靠性下降。----底層是xml,併發讀寫可能有問題的。
d.Application會多次創建。----運行在不同進程的組件是屬於不同虛擬機和Application。
二、IPC基礎概念 — Serializable接口、Parcelable接口、Binder
1、Parcelable和Serializable的區別
b、Parcelable是Andrord中的序列化方式,因此更適合用在Android平臺上,它的缺點就是使用起來稍微麻煩點,但是它的效率很高,這是Android推薦的序列化方式,因此我們要首選Parcelatle。
c、Parcelable主要用在內存序列化上,通過Parcelable將對象序列化到存儲設備中或者將對象序列化後通過網絡傳輸也都是可以的,但是這個過程會稍顯複雜,因此在這兩種情況下建議大家使用Serializabie。
2、Binder是什麼?
a、Binder是Android中的一個類,它實現了IBinder接口。b、從IPC角度來說,Binder是Android中的一種跨進程通信方式。
c、Binder還可以理解爲一種虛擬的物理設備,它的設備驅動是/dev/binder,該通信方式在Linux中沒有;
d、從AndroidFramework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager,等等)和相應Managerservice的橋樑:
e、從Android應用層來說,Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含了服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這裏的服務包括普通服務和基於AIDL的服務。
Android開發中,Binder主要用在Service中,包括AIDL和Messenger,其中普通Service中的Binder不涉及進程間通信,所以較爲簡單,無法觸及Binder的核心,而Messenger的的底層其實是AIDL>
3、Binder詳解
Binder工作機制:
兩點說明:
a、當客戶端發起遠程請求時,由於當前線程會被掛起直至服務器進程返回數據,所以如果一個遠程方法是很耗時的,那麼不能再UI線程中發起此遠程請求。b、由於服務器的Binder方法運行在Binder的線程池中,所以Binder方法不管是否耗時都應該採用同步的方式去實現,因爲他已經運行在一個線程中了。
Binder死亡:Binder運行在服務端進程,如果服務端進程由於某種原因異常終止,這個時候我們到服務端的Binder連接斷裂(稱之爲Binder死亡),會導致我們的遠程調用失敗。更爲關鍵的是,如果我們不知道Binder連接已經斷裂,那麼客戶端的功能就會受到影響。爲了解決這個問題,Binder中提供了兩個配對的方法linkTopeath和unlinkTopeath,通過 linkToDeath我們可以給Binder設置一個死亡代理,當Binder死亡時,我們就會收到通知,這個時候我們就可以重新發起連接請求從而恢復連接。那麼到底如何給Binder設置死亡代理成?也很簡單:
首先,生命一個Deathleciient對象、Deathleciient是一個接口,其內部只有一個方法binderDied,我們需要實現這個方法,當Binder死亡的時候,系統就會回調binderDied方法,然後我們就可以移出之前綁定的binder代理並重新綁定遠程服務;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if(mBookManager == null){
return;
}
mBookManager.asBinder().unlinkToDeath(mDeathRecipient,0);
mBookManager = null;
//這個可以重新綁定遠程service
}
};
其次,在客戶端綁定遠程服務成功之後,給binder設置死亡代理;
mService= IMessageBoxManager.Stub.asInterface(binder); binder.linkToDeath(mDeathRecipient,0);
其次linkToDeath的第二個參數爲標記位,我們直接設置爲0即可,經過上述的步驟,我們就可以給Binder設置死亡代理了,當Binder死亡之後我們就可以收到通知了,另外。通過Binder的方法isBinderAlive也可以判斷Binder是否死亡。
到這裏,IPC的基礎知識就介紹完畢了。
另外,