Android 程序間通訊(AIDL)
在Android平臺,一個程序通常不能訪問另一個程序的記憶體空間,所以要想對話,需要將物件分解成作業系統可以理解的基本單元,並且有序的通過程序邊界。通過程式碼來實現這個資料傳輸過程是冗長乏味的,Android提供了AIDL工具來處理這項工作。
AIDL (Android Interface Definition Language) 是一種IDL 語言,用於生成可以在Android裝置上兩個程序之間進行程序間通訊(interprocess communication, IPC)的程式碼。如果在一個程序中(例如Activity)要呼叫另一個程序中(例如Service)物件的操作,就可以使用AIDL生成可序列化的引數。
定義AIDL介面
AIDL介面檔案,和普通的介面內容沒有什麼特別,只是它的副檔名為.aidl。儲存在src目錄下。如果其他應用程式需要IPC,則那些應用程式的src也要帶有這個檔案。Android SDK tools就會在gen目錄自動生成一個IBinder介面檔案。service必須適當地實現這個IBinder介面。那麼客戶端程式就能繫結這個service並在IPC時從IBinder呼叫方法。
注意:每個aidl檔案只能定義一個介面,而且只能是介面的宣告和方法的宣告。
我們舉例說明:首先我們做一個在一個專案裡開啟多程序的例子。
1.專案工程列表如下:
MainActivity是執行在主程序的,ProcessService是執行在另一個程序中(實現方式看我的部落格 Android 多程序基礎)。
2.實現.aidl檔案
介面描述檔案
a、匯入的包名
b、如果有使用Object物件,需要該物件 implement Parcelable 介面,並且需要匯入該介面包名+類名;
如果是primitive type 不需要這步。
c、定義方法名稱。
d、所有的.aidl檔案已經需要傳遞的物件介面需要在Service 與Client中各一份
IStockService.aidl檔案
package com.example.processtest.aidl;
import com.example.processtest.aidl.Person;
interface IStockService {
double getResult(double a,double b);
com.example.processtest.aidl.Person getPerson();
}
如果aidl檔案中需要傳遞Object物件,需要新增對應的.aidl檔案
Person.aidl檔案
a、定義該物件Data,並實現Parcelable
b、新增Data.aidl檔案,並採用如下方式編寫匯入Data
c、需要在服務端和 客戶端都新增 Data.aidl與 Data.java檔案 並且需要一致。
package com.example.processtest.aidl;
parcelable Person;
新增 對應的Object類,並且實現Parcelable介面
public class Person implements Parcelable {
private String name;
private String age;
public Person(){
}
private Person(Parcel in){
readFromParcel(in);
}
public void readFromParcel(Parcel in)
{
name = in.readString();
age = in.readString();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public static final Parcelable.Creator<Person> CREATOR=new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
// TODO 自動生成的方法存根
return new Person(source);
}
@Override
public Person[] newArray(int size) {
// TODO 自動生成的方法存根
return new Person[size];
}
};
@Override
public int describeContents() {
// TODO 自動生成的方法存根
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO 自動生成的方法存根
dest.writeString(name);
dest.writeString(age);
}
}
3.在Service中實現.aidl 介面
實際實現的介面是在 gen中自動生成的 IaidlData.java的抽象內部類 Stub。
建立好.aidl檔案後,重新整理專案,在gen包對應的包下會出現與aidl檔案相同的Java檔案
AIDL工具生成的Java檔案中:
public static abstract class Stub extends android.os.Binder implements com.example.processtest.aidl.IStockService //靜態抽象內部類
private static class Proxy implements com.example.processtest.aidl.IStockService //AIDL服務代理類
public double getResult(double a, double b) throws android.os.RemoteException //AIDL公佈出的介面,就是我們定義的介面方法。
AIDL只是一個契約,我們需要一個服務來提供服務。
提供服務的類ProcessService
public class ProcessService extends Service {
private class IStockServiceImp extends IStockService.Stub{
@Override
public double getResult(double a, double b) throws RemoteException {
// TODO 自動生成的方法存根
return a+b;
}
@Override
public Person getPerson() throws RemoteException {
// TODO 自動生成的方法存根
Person person=new Person();
person.setAge("20");
person.setName("zhangsan");
return person;
}
}
@Override
public IBinder onBind(Intent intent) {
// TODO 自動生成的方法存根
return new IStockServiceImp();
}
@Override
public boolean onUnbind(Intent intent) {
// TODO 自動生成的方法存根
//關閉服務所在的程序
android.os.Process.killProcess(android.os.Process.myPid());
return super.onUnbind(intent);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO 自動生成的方法存根
Log.d("xxx",
android.os.Process.myPid() + ";"
+ Tools.getCurProcessName(getApplicationContext()));
Log.d("xxS", MyApplication.name);
return super.onStartCommand(intent, flags, startId);
}
}
4.程序間的通訊
public class MainActivity extends Activity {
private IStockService service2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("xxM", android.os.Process.myPid() + "");
Intent intent = new Intent(getApplicationContext(),
ProcessService.class);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
Log.d("xxM", MyApplication.name);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO 自動生成的方法存根
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO 自動生成的方法存根
service2 = IStockService.Stub.asInterface(service);
try {
Log.d("xx", service2.getResult(5, 9) + "");
Log.d("xxp", service2.getPerson().getAge() + ";"
+ service2.getPerson().getName());
} catch (RemoteException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
}
};
public boolean onKeyDown(int keyCode, android.view.KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
finish();
// 退出程式時我們一般只調用finish()函式殺死當前Activity,Application退到幕後,由系統自動維護。
// 再次啟動程式時就不會執行Application.onCreate(),而是直接執行Activity.onCreate()。
//殺掉程序的方法
android.os.Process.killProcess(android.os.Process.myPid());
return true;
}
return false;
};
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
};
}