1. 程式人生 > >Android 關於IPC機制的理解(一)

Android 關於IPC機制的理解(一)

IPC是什麼

IPC(Inter-Process Communication)指的是程序間通訊,也就是兩個程序之間進行資料互動。理解這個首先得知道什麼是程序,初學者可能會對程序跟執行緒有所混淆,其實程序和執行緒是兩個不同的概念,執行緒是CPU排程的最小單元,而程序是一個執行單元,在Android中它可以指一個應用(當然一個應用可以有多個程序),他們是一對多的關係,一個程序可以裡面可以包含多個執行緒也可以只包含一個執行緒,比如一個app中只有一個程序,裡面有個主執行緒,然後我們也可以使用new Thread()方法去建立多個執行緒,當然直接用匿名內部類來開啟執行緒是有很多弊端的,比如執行緒沒得到管理影響效能,執行緒間競爭佔用系統資源,用這個方法有可能會造成記憶體洩露,所以java也提供了四種執行緒池策略,讓我們可以自己執行緒建立,銷燬,這屬於題外話就不多累贅了..回到IPC機制中,這個機制並不是只有Android系統才有,任何系統都會涉及程序間通訊,所以都會有自己的一套機制來進行程序間的通訊。程序間通訊在Android中有兩種,一種是兩個應用見要涉及某些資料的通訊,比如在淘寶中跳轉到支付寶頁面,另一種是一個應用採取了多程序的模式,下面是我手機的截圖


可以看到支付寶就存在了兩個程序,一個應用採用多程序的原因可能有很多,比如某些模組要執行在單獨的程序中,或者為了讓應用可以獲得系統分配的更大記憶體空間。但是注意的是你的應用採用了多程序的設計方法,那麼你就該謹慎妥善的處理程序間通訊的各種問題。

下面講一下怎麼在一個應用中開啟多程序,開啟多程序的方法是在清單檔案註冊四大元件時指定android:process屬性,用現象來說明事實是很好的學習方法,我做了個示例

在清單檔案註冊了三個Activity同時指定了它們的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=".TestActivity1"
            android:process=":test" />
        <activity
            android:name=".TestActivity2"
            android:process="com.sjr.ipcdemo.test" />
我為TestActivity1和TestActivity2指定了不同的process值,然後我們看看結果然後分析,結果如下:

如上圖,當我們不指定process屬性則執行在預設程序中,預設程序名就是包名,還有一個值得說明的是以":"開頭的程序屬於應用的是有程序,其他應用不能和它在一個程序中執行,":"是在當前程序名的前面附上當前包名的簡寫,而只要不以":"開頭這個程序就屬於全域性程序,其他應用可以通過ShareUID方式和它跑在同一程序中,但是注意的是比如com.sjr.ipcdmo.test這個程序不能直接簡寫成.test如果直接寫成.test程序名就是.test而不會附加上包名。

使用多程序會出現的問題

上面已經說了多程序的建立,建立多程序並不困難,只要指定process屬性就可以了,但是多程序真的這麼簡單嗎,其實可能在實際使用多程序中會碰到很多問題下面對問題進行一個個分析:

(1)靜態成員變數和單例模式失效

示例如下:

public class TestBean {
    public static int number = 1;
}

我在TestBean類裡定義了一個靜態成員變數,並賦初始值為1,然後在MainActivity的onCreate方法裡把值改成了2;然後啟動TestActivity1並獲取number的值,再啟動TestActivity2並獲取number的值,照正常情況來說靜態變數在記憶體中是所有物件共享的,我在MainActivity中修改了這時在TestActivity1和TestActivity2獲取時值應該是2才對,但是結果如何呢,我們打Log來看下,Log如下:


從Log可以看到TestActivity1和TestActivity2獲取的number值還是1,這就是使用多執行緒會出現的問題之一了,出現的原因是Android會為每個程序分配不同的虛擬機器,而不同的虛擬機器在記憶體中分配的地址空間就不一樣了,從這個例子來說就是三個程序產生了三個不同的記憶體地址,所以當虛擬機器訪問TestBean類時會產生三個副本,所以修改MainActivity中的number是不影響其他兩個的。

(2)執行緒同步機制失效

從第一點已經知道,既然不在同一個記憶體中,那鎖的物件肯定不是同一個了,所以也就不存線上程同步這一說了。

(3)SharePreferences使用異常

sp底層是通過讀/寫xml來儲存資料的鍵值對,按我們正常理解來說共享資料的方式實現程序間通訊是可以的,但是Android對sp的讀寫有自己的快取策略,在讀寫的時候記憶體中也會有一份sp的快取,所以多程序的時候也是有問題的,當然說到共享資料實現程序間通訊業需要考慮資料併發的問題了,這不在本文詳述。

(4)Application建立多次

我們知道當一個新程序啟動Android會分配一個新的虛擬機器並劃分新的記憶體地址,當我啟動新的程序就說明系統會重新會重新啟動一次,然後因為記憶體地址不同就分配另個Application給當前程序了,下面用例子來試驗:

public class MApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("print", "MApplictation pid:" + Process.myPid());
    }
}
我新建了一個Application然後照著前面的順序依次啟動TestActivity1和TestActivity2,同一程序時這個Application只會建立一次,但是不同程序啟動時會建立一次,Log如下:

可以看到建立了三次Application,所以當我們把初始化操作放在Application中時,如果應用存在多執行緒就會建立多次Application,也就會初始化多次應用的一些操作,這會影響到應用的效能,這點是需要注意的。