本文為Android的IPC相關(guān)知識整理,具體參考了
- 《Android開發(fā)藝術(shù)探索》第二章 IPC機(jī)制
IPC,Inter-Process Communicatoin的縮寫。即為Android進(jìn)程間通信。
1,進(jìn)程與線程
- 線程是CPU調(diào)度的基本單位,進(jìn)程一般指一個執(zhí)行單元,在移動設(shè)備上指一個應(yīng)用或者是一個程序。一個進(jìn)程包含一個或多個線程。
- 在Android中,一個程序可以只有一個線程,即主線程,也叫UI線程。在UI線程中才能操作界面元素,而不能在UI線程中執(zhí)行大量耗時任務(wù),否則會造成ANR,Application not responding錯誤。
Android線程(Thread)間通信:
- Handle和Looper配合,消息隊列機(jī)制。我們可以用AsyncTask類這個異步任務(wù)類。
- 訪問其他應(yīng)用程序的Activity,通過Intent附帶信息
IntentcallIntent= newIntent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent); - ContentProvider,例如訪問系統(tǒng)相冊,通訊錄,短信等
- Broadcast 廣播
- AIDL,Android接口定義語言
Android進(jìn)程(Process)間通信:
- Binder
- Socket
- 文件共享
- ContentProvider
- Intent
- Messenger
2,Android中的多進(jìn)程
在Android中使用多進(jìn)程只有一種方法,即給四大組件在AndroidManifest中指定android:process屬性。
<activity
android:name="com.ryg.chapter_2.MainActivity"
android:label="@string/app_name">
<intent-filter>
....
</intent-filter>
</acitivty>
<activity
android:name="com.ryg.chapter_2.SecondAcitvity"
android:process=":remote"/>
<activity
android:name="com.ryg.chapter_2.ThirdAcitvity"
android:process="com.ryg.chapter.remote"/>
以上三個activity分別在以下進(jìn)程中:
- com.ryg.chapter_2,沒有為組件指定process,那么這個組件就會運(yùn)行在默認(rèn)進(jìn)程中。
- com.ryg.chapter_2:remote,冒號的含義是在當(dāng)前的進(jìn)程名上附加當(dāng)前的包名,此進(jìn)程屬于當(dāng)前應(yīng)用的私有進(jìn)程。
- com.ryg.chapter_2.remote,進(jìn)程名不以冒號開頭的進(jìn)程屬于全局進(jìn)程,其他應(yīng)用通過ShareUID方式可以和它跑在同一個進(jìn)程中。
由于Android會為每一個進(jìn)程提供單獨(dú)的虛擬機(jī),不同的虛擬機(jī)在內(nèi)存分配上有不同的地址空間,因而在不同的虛擬機(jī)中訪問同一個類對象會產(chǎn)生多份副本。不同進(jìn)程的虛擬機(jī),Application,內(nèi)存空間都不一樣!?。?!相當(dāng)于兩個不同的應(yīng)用采用了SharedUID模式。
多進(jìn)程引起的問題:
- 靜態(tài)成員和單例模式失效
- 線程同步機(jī)制失效
- SharedPreferences可靠性下降,其不支持兩個進(jìn)程同時執(zhí)行寫操作。
- Application會多次重建
3,IPC基礎(chǔ)概念
當(dāng)我們需要通過Intent和Binder傳輸數(shù)據(jù)時,需要使用Serializable和Serializable接口來完成對象的序列化。
當(dāng)我們需要使對象持久化到存儲設(shè)備上時,需要使用Serializable來完成對象的持久化。
3.1 Serializable接口
這個是Java自帶的,很簡單但是內(nèi)存開銷大,只需要在類中加入serialVersionUID。適用于將對象序列化到存儲設(shè)備或者將對象序列化后通過網(wǎng)絡(luò)進(jìn)行傳輸。
public class User implements Serializable{
private static final serialVersionUID = 4132904873290147032L;
public int userId;
public String userName;
public boolean isMale;
}
序列化和反序列化過程
//序列化
User user = new User(0, "jake",true;);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
//反序列化
ObjectInputStream in= new ObjectInputStream(new FileInputStream("cache.txt"));
User newUser = (User)in.readObject();
in.close();
恢復(fù)后的newUser對象和user內(nèi)容完全一致,但不是同一對象。
為了避免反序列化失敗,serialVersionUID 一般應(yīng)該手動指定?。。?/strong>其實(shí)也可以不指定serialVersionUID ,但這樣的話是IDE自動根據(jù)類結(jié)構(gòu)去生成hash值,這樣的話我們對其的控制力就弱了,如果改變了類結(jié)構(gòu),就不能反序列化了?。。?!而手動指定serialVersionUID 可以最大限度恢復(fù)數(shù)據(jù)。
3.2 Parcelable接口
這個是Android獨(dú)有的,更適合用在Android平臺,效率高,但是用起來有點(diǎn)麻煩。
public class User implements parcelable{
public int userId;
public String userName;
public boolean isMale;
public User(int userId, String userName, boolean isMale){
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}
public Book book;
//內(nèi)容描述
public int describeContents(){
return 0;
}
//序列化
public void writeToParcel(Parcel out, int flags){
out.writeInt(userId);
out.writeString(userName);
out.writeInt(isMale ? 1 : 0);
out.writeParcelable(book, 0 );
}
//反序列化
public static final Parcelable.Creator<user> CREATOR = new Parcelable.Creator<User>(){
//從序列化后的對象中創(chuàng)建原始對象
public User createFromParcel(Parcel in){
return new User(in);
}
//創(chuàng)建指定長度的原始對象
public User[] newArray(int size){
return new User[size];
}
};
private User(Parcel in){
userId = in.readInt();
userName = in.readString();
isMale = in.readInt() = 1;
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
}
}
3.3 Binder
- 從IPC角度看,Binder是一種跨進(jìn)程通信方式。
- 從Android Freamwork角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager)和相應(yīng)ManagerService的橋梁。
- 從Android應(yīng)用層將,Binder是客戶端和服務(wù)器進(jìn)行通信的媒介。
Android開發(fā)中,Binder主要用在Service中,包括AIDL,Messenger。