Android AIDL淺析(一)
阿新 • • 發佈:2019-01-22
一、什麼是AIDL?
- AIDL是一個縮寫,全稱是Android Interface Definition Language,也就是Android介面定義語言;
- AIDL是進行程序間通訊的常用方式
二、怎麼使用AIDL?
- 總體來說,使用AIDL的過程可以總結為:
-
- 定義AIDL介面
- 服務端對AIDL介面進行邏輯補全
- 客戶端通過AIDL介面呼叫服務端邏輯進行各種操作
資料跨程序傳輸過程就在這種呼叫與被呼叫過程中通過binder進行
程式碼詳析(非原始資料型別):
1. 待傳輸物件類:
public class People implements Parcelable {
private String name;
private int age;
private String sex;
//無參建構函式
public People() {
name = "";
age = 0;
sex = "";
}
//一般建構函式,提供給使用者構造People物件
public People(String name, int age, String sex) {
this.name = name;
this.age = age;
this .sex = sex;
}
//Android studio可自動生成,提供給系統 Creator 生成People物件
protected People(Parcel in) {
name = in.readString();
age = in.readInt();
sex = in.readString();
}
//這個物件是AIDL中tag為in或inout時候呼叫的,即從序列化流中建立people物件的時候呼叫
public static final Creator<People> CREATOR = new Creator<People>() {
@Override
public People createFromParcel(Parcel in) {
return new People(in);
}
@Override
public People[] newArray(int size) {
return new People[size];
}
};
//Parcel的內容包含檔案描述符,一般傳0
@Override
public int describeContents() {
return 0;
}
//如果你需要使用out或inout的tag的話,就要自己定義這個函式,它目的是通過流修改當前people物件的屬性
public void readFromParcel(Parcel parcel) {
name = parcel.readString();
age = parcel.readInt();
sex = parcel.readString();
}
//將為tag為in的資料寫入流中傳輸
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
parcel.writeString(sex);
}
//無特殊意義,只是為了方便顯示
@Override
public String toString() {
return name + ", " + age + " years old, is a " + sex;
}
2. 待傳輸物件的AIDL檔案(AIDL類1):
package com.AIDL_demo;
parcelable People;//只需要宣告本類為parcelable
3. 定義介面方法的AIDL(AIDL類2):
package com.AIDL_demo;
import com.AIDL_demo.People;
interface IMethod {
List<People> getPeople();
}
4. 服務端:
public class MyService extends Service {
List<People> people = new ArrayList<>();
private final IMethod.Stub method = new IMethod.Stub() {
@Override
public List<People> getPeople() throws RemoteException {
return people;
}
};
public MyService() {
People man1 = new People("Mike", 18, "male");
people.add(man1);
People man2 = new People("Lucy", 26, "female");
people.add(man2);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return method;
}
}
5. 客戶端關鍵程式碼:
//跨程序啟動service
public void bindRemoteService() {
Intent intent = new Intent();
intent.setAction("my_remote_service");//manifest中service的action
intent.setPackage("com.AIDL_demo");//服務端的package名
bindService(intent, connection, Service.BIND_AUTO_CREATE);
}
private IMethod method;
private final ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
method = IMethod.Stub.asInterface(iBinder);//獲取遠端服務端的AIDL通訊物件
if (method == null) {
Log.d("LogTag", "IMethod is null");
return;
}
try {
List<com.AIDL_demo.People> peopleList = method.getPeople();//呼叫遠端介面獲取服務端資料
//列印資料
StringBuilder stringBuilder = new StringBuilder();
for (People people : peopleList) {
stringBuilder.append(people.toString());
stringBuilder.append("\n");
}
Log.d("LogTag", stringBuilder.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("LogTag", "service disconnected");
}
};
- 最終執行會在客戶端Logcat中列印:
- D/LogTag: Mike, 18 years old, is a male
Lucy, 26 years old, is a female
結論:成功跨程序通訊,將服務端建立的兩個People物件,傳輸到了客戶端;
注意事項
- AIDL檔案必須和這個非原始資料類在同名包下,只是一個在Java目錄下,一個在AIDL目錄下:
- AIDL中在引數為非預設資料型別的變數時,都需要設定定向的tag
ADIL中預設支援Java八大基本型別和String,CharSequence,List(元素必須是AIDL支援的,List可以使用泛型),Map(元素必須是AIDL支援,Map不支援泛型);
AIDL檔案可以分為兩類。一類是用來定義非預設支援的資料型別,以供其他AIDL檔案使用的,如上面程式碼中的 “AIDL類1” ;一類是用來定義方法介面,用來完成跨程序通訊的,如上面程式碼中的 “AIDL類2” 。