說到AIDL,每次就配套一個單詞就是IPC,到底是怎麼一回事,這事得從多進程說起。
有一天,我們寫了一個類,類裏面有一個靜態變量。就像下面這樣
public class UserBean {
public static int userCount=0;
}
原本的需求是這樣的,通過這個User類的一個靜態值,來全局共享一些用戶信息,提供給A和B顯示用,而這A和B是在兩個獨立的進程中(非線程)的,同時要求對這個數據有讀寫的能力。
關於如何開啓多進程,估計很多程序是用不到的,因爲他的場景不是很廣泛,我們有可能是採用別的方案就避免掉了,例如廣播之類的。
開啓多進程的方法就是在我們的xml配置文件加多process屬性,如下:
<activity
android:name=".activity.Test2Activity"
android:process=".newProcess1" />
<service
android:name=".service.MyDemoService"
android:enabled="true"
android:exported="true"
android:process=":newProcess2" />
是不是很簡單的感覺就可以開多進程了?
這裏有一點需要注意的就是我們在名字前面的符號是什麼,一個是“ : ”,另外一個是“. ”
兩者導致的就是進程的名字不一樣而已,同時如果以“:”開頭,表示該進程爲當前應用私有,和其他的組件是不會跑在同一個進程中的。後者是全局進程,可以和別的組件跑在同個進程,然後進行數據共享的。具體的內容以後再補充吧,說多有感覺跑遠了。
現在假設我們先啓動了A進程,然後設置值爲1,接着啓動B進程,打印數據,理論是等於1纔對。
public class A{
UserBean.userCount=1;
}
public class B{
Log.e(TAG, "count="+UserBean.userCount);
}
但我們居然發現打印是0, 這可壞了,這是爲啥呢?
我們很當然的要懷疑起這個多進程到底怎麼了?
簡單的說就是,在安卓上,多進程就代表了”同時運行多個同樣的app“。
既然是兩個同時運行的A和B,那兩者想讓就互補影響了。
不知有沒映像,以前在諾基亞的塞班S60時代手機上有QQ共存版 ,同時運行多個QQ,每個QQ收到的數據是互不影響的,多進程大抵就是這種樣子。
多進程帶來的問題當然不知這些啦,我們的單例模式,線程同步等都顯然形同虛設了,但需求還在那,我們需要把這事幹了啊,那怎麼辦呢?
我們的不同進程要進行溝通解決啦,所以就有了這樣那樣的進程間進行通訊的機制(IPC)。
IPC有哪些?
能做進程間通訊的常見的有基於Binder的messenger,AIDL和Socket。據聞基於binder的效率最高,具體怎麼比出來的,我也沒看過。另外還有SharedPreferences,ContentProvider,Bundle等
AIDL
我們先寫一個接口文件,用來給別的進程調用用的,這裏我們提供一對get/set方法。
// UserManagerInterface.aidl
interface UserManagerInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
int getUserCount();
void setUserCount( in int n);
}
接着我們谷歌說的要求,寫這麼個獨立的類,裏面只有下面那個
// UserBean.aidl
package com.example.sanjay.myapplication.aidl;
parcelable UserBean;
最後我們再寫一個簡單的UserBean類
public class UserBean implements Parcelable {
public static int UserCount=0;
private String userName;
protected UserBean(Parcel in) {
userName = in.readString();
}
public static final Creator<UserBean> CREATOR = new Creator<UserBean>() {
@Override
public UserBean createFromParcel(Parcel in) {
return new UserBean(in);
}
@Override
public UserBean[] newArray(int size) {
return new UserBean[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(userName);
}
}
整個的結構就這樣
然後爲了我們的演示方便,我們在service裏面加多一個類,如下,很簡單,沒什麼特別要說的
public class AidlService extends Service {
private final UserManagerInterface.Stub mBidnerStub = new UserManagerInterface.Stub() {
@Override
public int getUserCount() throws RemoteException {
return UserBean.UserCount;
}
@Override
public void setUserCount(int n) throws RemoteException {
UserBean.UserCount = n;
}
};
public AidlService() {
}
@Override
public IBinder onBind(Intent intent) {
return mBidnerStub;
}
}
接着在我們的其中一個寫下面的內容
public class MainActivity extends BaseActivity {
private static final String TAG = MainActivity.class.getSimpleName();
UserManagerInterface mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.e(TAG, "connect service");
mService = UserManagerInterface.Stub.asInterface(service);
try {
Log.e(TAG, "curUserCount=" + mService.getUserCount());
mService.setUserCount(2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "disconnect service");
mService = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, AidlService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
好了,核心的內容就這麼點啦。基本都配置好了。
現在我們就可以做跨進程的通訊工作了。
由於時間限制,今天先寫到這裏,明天再補充