
不同進(jìn)程之間的應(yīng)用一般是不進(jìn)行通信,就像在兩個(gè)獨(dú)立的房屋,各自有自己的系統(tǒng)。如若有特定需求,方然也是可以實(shí)現(xiàn)的。
跨進(jìn)程通信方式
- 跨進(jìn)程訪問(wèn)Activity,通過(guò)一個(gè)Action來(lái)完成的,如果要傳遞數(shù)據(jù),還需 要指定一個(gè)Uri。
- Content Provider ,通過(guò)共享本地?cái)?shù)據(jù)庫(kù),實(shí)現(xiàn)進(jìn)程之間的數(shù)據(jù)傳輸
- 廣播(Broadcast),當(dāng)某個(gè)程序向系統(tǒng)發(fā)送廣播時(shí),其他的應(yīng)用程序只能被動(dòng)地接收廣播數(shù)據(jù)。
- AIDL,接口定義語(yǔ)言;
這一篇,主要記錄通過(guò)AIDL實(shí)現(xiàn)進(jìn)程之間的通信,和數(shù)據(jù)的傳輸。
AIDL
開發(fā)Android這么久,第一次知道,還能創(chuàng)建.aidl文件,編譯后,還能自動(dòng)生成另外一個(gè)文件,頗為神奇。那接下來(lái)開始AIDL學(xué)習(xí)
創(chuàng)建AIDL文件
在指定目錄下創(chuàng)建后綴名為.aidl文件,創(chuàng)建的文件類似于接口interface,在里面可以定義抽象方法,實(shí)現(xiàn)具體的業(yè)務(wù)需要。
注:這里有個(gè)坑,在
.aidl文件中,編譯器并不會(huì)對(duì)其進(jìn)行校驗(yàn),一些語(yǔ)法錯(cuò)誤也不會(huì)爆紅顯示,還有import文件時(shí),一定要保證路徑的正確,和精確到需要導(dǎo)入的類名。
interface IRemoteService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
//定義抽象方法
String getName(int id);
}
創(chuàng)建Service
然后可以創(chuàng)建獨(dú)立進(jìn)程的Service,,具體的業(yè)務(wù)邏輯操作均可放在這里。其中需要是實(shí)現(xiàn)一個(gè)重要的方法,與AIDL文件關(guān)聯(lián)起來(lái)。就是Binder,這是一個(gè)在Android源碼整體中,最普遍存在,使用率最多的一個(gè)對(duì)象。它就像國(guó)外城市里的地下水道,聯(lián)通著每一個(gè)環(huán)節(jié),起到傳輸?shù)淖饔?。在onBind方法中 return該Binder
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString)
throws RemoteException {
}
//實(shí)現(xiàn)抽象方法
@Override
public String getName(int id) throws RemoteException {
return names[id];
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
Service建好之后,總需要跑起來(lái)吧,然后才能被調(diào)用到。這里把這個(gè)Service放到獨(dú)立進(jìn)程中,在AndroidMainfest.xml中將Service配置
<service
android:name=".testaidl.RemoteService"
android:process=":RemoteService">
<intent-filter>
<action android:name="com.intent.action.RemoteService"/>
</intent-filter>
</service>
綁定Service,并調(diào)用
這里對(duì)Service調(diào)用方式實(shí)現(xiàn)隱性調(diào)用。通過(guò)這個(gè)Action標(biāo)簽,去識(shí)別這個(gè)Service,并且我將其放在獨(dú)立的RemoteSerice進(jìn)程中。實(shí)際中將它啟動(dòng)并綁定。
bindService(new Intent("com.intent.action.RemoteService"), new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mRemoteService = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name ){
}
}, BIND_AUTO_CREATE);
這樣我們就可以看到,后臺(tái)有兩個(gè)進(jìn)程啟動(dòng)著
圖片。。。。。
然后可以再創(chuàng)建一個(gè)應(yīng)用,在其Acitity綁定這個(gè)Service,這樣就相當(dāng)于獲取了這個(gè)AIDL對(duì)應(yīng)的mRemoteService對(duì)象,可以對(duì)其中的抽象方法進(jìn)行調(diào)用。也就實(shí)現(xiàn)了在這個(gè)應(yīng)用中調(diào)用,另外一個(gè)應(yīng)用中的方法。而且,可以進(jìn)行參數(shù)的傳送,這里我傳了了一個(gè)int的參數(shù)
public void search(){
if(isConnSuccess){
// 連接成功
int id = Integer.valueOf(mEditText.getText().toString());
try {
String name = mRemoteService.getName(id);
mTv_result.setText(name);
}catch (RemoteException ex) {
ex.printStackTrace();
}
}else{
System.out.println("連接失敗!");
}
}
通過(guò)AIDL實(shí)現(xiàn)對(duì)象傳傳遞
進(jìn)階稍微更高一階的話,實(shí)現(xiàn)對(duì)象的傳參。
同樣的,在第一個(gè)應(yīng)用中,創(chuàng)建一個(gè)Person的類,并且同時(shí)在相同目錄下面創(chuàng)建AIDL文件,這個(gè)Person類必須進(jìn)行Parcelable序列化,至于為什么,我想可能和Android機(jī)制有關(guān)。在AIDL文件中也只要對(duì)這個(gè)類進(jìn)行序列化定義就ok。
package com.example.porterking.keepliveapplication.testaidl;
// Declare any non-default types here with import statements
parcelable Person ;
在原來(lái)的IRemoteService.aidl文件中對(duì)這個(gè)類進(jìn)行調(diào)用
import com.example.porterking.keepliveapplication.testaidl.Person;
// Declare any non-default types here with import statements
interface IRemoteService {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
Person getPerson(int id);
}
這里需要注意的就是 Person類字啊AIDL文件中,不會(huì)自動(dòng)導(dǎo)入,需要手動(dòng)將類的路徑import進(jìn)來(lái),精確到類名。而后和之前的方法實(shí)現(xiàn)步驟一致。在自己定義在獨(dú)立進(jìn)程中的Service中實(shí)現(xiàn)這個(gè)getPerson抽象方法。再在Activity中實(shí)現(xiàn)調(diào)用就好哦
public void searchObject(View view){
if(isConnSuccess){
// 連接成功
int id = Integer.valueOf(mEditText.getText().toString());
try {
Person person = mRemoteService.getPerson(id);
mTv_result.setText("姓名:"+person.getName()+" 年齡:"+person.getAge());
}catch (RemoteException ex) {
ex.printStackTrace();
}
}else{
System.out.println("連接失敗!");
}
}