Android IPC機制
Android中多進程模式
如何開啟多進程模式
在Android中只有一種方法,那就是在AndroidMenifest
文件中給四大組件(Activity,Service,Receiver,ContentProvider)指定android:process
屬性
- 使用
:
的進程是當前應用的私有進程,其他應用組件不能和它跑在同一個進程 - 使用
.
是全局進程,其他應用通過ShareUID方式可以和它跑在同一個進程
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MessengerActivity"
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=":rcom.zhc.androidarttravel.remote">
</activity>
<!--使用冒號,默認會補全包名,與上述activity不是同一個進程 -->
<service
android:name=".service.MessengerService"
android:process=":remote" />
<activity android:name=".MainActivity"></activity>
</application>
多進程模式的運行機制
- Android為每一個進程分配了一個獨立的虛擬機,具有不同的地址空間,導致每個虛擬機訪問同一個類會產生多個副本,也就是說兩個虛擬機數據、對象不共享,各用個的(在一個進程中改變了值,在另一個進程中不會改變,是兩個單獨的空間)
問題:
- 靜態成員和單例設計模式完全失效
- 線程同步機制完全失效(不同進程鎖的對象不同)
- SharedPreferences的可靠性降低(不支持兩個進程同時執行寫操作,會導致數據丟失)
- Application會多次創建(不同進程是不同的虛擬機,就是需要重新啟動應用,所以創建新的Application)
IPC基礎介紹
Serializable與Parcelable
區別:
- Serializable是Java中的序列化接口,使用簡單但是開銷大,因為序列化和反序列化是需要大量的I/O操作
- Parcelable是Android中的序列化方式,高效但稍顯麻煩,首選Parcelable
- 但是在序列化存儲到設備中或將對象序列化后通過網絡傳輸還是用Serializable,更方便
Serializable接口
只需要在類中聲明一個serialVersionUID
,也可以不需要指定UID,這個UID是在反序列化的時候判斷一下是否是相同的UID對象,相同才可以反序列化
這種方式要避免并發讀寫,內容可能不是最新,
-
該方式適合對數據同步要求不高的進程之間通信
//值隨便取,唯一即可
private static final long serialVersionUID = 2313186133168643352l;
序列化過程,采用ObjectOutputStream
和ObjectInputStream
,例如下:
//序列化
try {
User user = new User("zhc",007,true);
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
//反序列化
try {
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("cache.txt"));
User newUser = (User) in.readObject();
in.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
反序列化后的對象內容和之前的一樣,但是是兩個不同的對象
Parcelable
先定義好變量和構造方法再實現接口
public class UserP implements Parcelable {
private String userName;
private int userID;
private boolean isMale;
public UserP(String userName, int userID, boolean isMale) {
this.userName = userName;
this.userID = userID;
this.isMale = isMale;
}
protected UserP(Parcel in) {
userName = in.readString();
userID = in.readInt();
isMale = in.readByte() != 0;
}
//反序列化,配合以上方法
public static final Creator<UserP> CREATOR = new Creator<UserP>() {
@Override
public UserP createFromParcel(Parcel in) {
return new UserP(in);
}
@Override
public UserP[] newArray(int size) {
return new UserP[size];
}
};
@Override
public int describeContents() {
return 0;
}
//序列化
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(userName);
parcel.writeInt(userID);
parcel.writeByte((byte) (isMale ? 1 : 0));
}
}
Android中的IPC方式
使用Bundle
四大組件中的三大組件都可以用Bundle來傳遞數據,對象序列化之后也可以放入Bundle來傳遞,基本數據類型和String都是實現了序列化的。
使用文件共享
由于Android是基于Linux的,使得其并發讀/寫文件可以沒有限制的進行,寫序列化文件到SD卡中存儲,另一個進程讀取
//序列化
public void persistToFile() {
new Thread(new Runnable() {
@Override
public void run() {
User user = new User("zhc",007,true);
File dir = new File(MyConstants.CHAPTER_2_PATH);
if (dir != null){
dir.mkdirs();
}
ObjectOutputStream outputStream = null;
File cacheFile = new File(MyConstants.CACHE_FILE_PATH);
try {
outputStream =
new ObjectOutputStream(new FileOutputStream(cacheFile));
outputStream.writeObject(user);
Log.d("user","persist File : " + user);
} catch (IOException e) {
e.printStackTrace();
}finally {
MyUtils.close(outputStream);
}
}
}).start();
}
//反序列化
public void recoverFromFile() {
new Thread(new Runnable() {
@Override
public void run() {
User newUser = null;
ObjectInputStream objectInputStream = null;
File cacheFile = new File(MyConstants.CACHE_FILE_PATH);
if (cacheFile.exists()) {
try {
objectInputStream = new ObjectInputStream(
new FileInputStream(cacheFile));
newUser = (User) objectInputStream.readObject();
Log.d("user", "recover from File : " + newUser);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
MyUtils.close(objectInputStream);
}
}
}
}).start();
}
使用Messenger
Messenger是信使,他可以在不同進程中傳遞message對象,底層實現是AIDL,對AIDL進行了封裝。它一次只處理一個請求,因此在服務端不用考慮線程同步的問題。