在上一篇博客《跨進(jìn)程間如何進(jìn)行AIDL IPC 通信(一)》中,我們只介紹了基本類型參數(shù)的AIDL IPC通信脏榆,如果想傳遞一個復(fù)雜的類型覆劈,那該如何處理呢,幸好Android支持AIDL傳遞自定義類型吃度,今天我們將著重介紹自定義類型如何在不同的進(jìn)程間進(jìn)行傳遞甩挫。
1. Service端
a) 創(chuàng)建一個自定義類
創(chuàng)建一個自定義對象,咱們還是以Person為例椿每,該對象必須完成以下動作:
- 實(shí)現(xiàn)Parcelable接口伊者,并且實(shí)現(xiàn)Parcelable接口的public void writeToParcel(Parcel dest, int flags)方法,因為任何復(fù)雜的自定義對象都是由基本類型封裝而成间护,因此傳輸自定義類型時亦渗,只要將其拆分成基本類型,而Parcelable接口就是用來約定數(shù)據(jù)被序列化傳輸?shù)姆绞街摺ublic int describeContents():內(nèi)容接口的描述法精,通常直接返回0即可
public void writeToParcel(Parcel parcel, int i):用于將當(dāng)前類的成員寫入到Parcel容器中,重寫該方法時調(diào)用Parcel類的write系列方法即可痴突。如writeInt(),writeString()等搂蜓。 - 自定義類型中必須含有一個名稱為CREATOR的靜態(tài)成員,該成員對象要求實(shí)現(xiàn)Parcelable.Creator接口及其方法苞也。
- 通常還需要我們自定義readFromParcel(Parcel parcel)方法洛勉,用于從Parcel容器中讀出數(shù)據(jù),讀出的順序必須與寫入時的順序一致如迟。
其實(shí)在Android Studio實(shí)現(xiàn)上述兩點(diǎn)時非常簡單收毫,只要鼠標(biāo)放點(diǎn)擊Parcelable接口上,按下alt + enter快捷鍵殷勘,選擇Implement methods即可自動完成實(shí)現(xiàn)第一點(diǎn)的編碼此再;再次將鼠標(biāo)放于Person 類上,按下alt + enter快捷鍵玲销,選擇Add Parcelable Implementation, 即可自動完成第二點(diǎn)的編碼输拇。
public class Person implements Parcelable {
private String name;
private int age;
public Person(){
}
protected Person(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
}
public void readFromParcel(Parcel reply) {
this.name = reply.readString();
this.age = reply.readInt();
}
}
b) 創(chuàng)建一個aidl文件聲明你的自定義類型
在自定義類型所在包下創(chuàng)建一個aidl文件對自定義類型進(jìn)行聲明,文件的名稱與自定義類型同名贤斜。 聲明方式
parcelable Person;
如圖1所示:
c) 在接口aidl文件中使用自定義類型
需要使用import顯式導(dǎo)入Person策吠,in,out,inout為數(shù)據(jù)流向
import tech.onroad.aidlserverdemo.bean;
interface IOnroad {
String sayHello(String name, int age);
void introducePerson(inout Person person);
}
d) 實(shí)現(xiàn)aidl文件生成的接口
本例是OnroadService逛裤,但并非直接實(shí)現(xiàn)接口,而是通過繼承接口的Stub來實(shí)現(xiàn)(Stub抽象類內(nèi)部實(shí)現(xiàn)了aidl接口)猴抹,并且實(shí)現(xiàn)接口方法的代碼带族。內(nèi)容如下:
private IOnroad.Stub mBinder = new IOnroad.Stub() {
@Override
public String sayHello(String name, int age) throws RemoteException {
String str = "Hello " + name + ", your age is " + age;
Log.d(TAG, str);
return str;
}
@Override
public void introducePerson(Person person) throws RemoteException {
Log.d(TAG, "My name is " + person.getName() + ", I am " + person.getAge());
}
};
至此,Service端的工作已完成蟀给。
2. Client端
a) 同理將service端的aidl文件及aidl對應(yīng)的java文件復(fù)制到client端
目錄結(jié)構(gòu)如圖2所示:
b) 同理蝙砌,為圖省事,我們同樣在onServiceConnected()方法里調(diào)用我們的自定義類型參數(shù)AIDL接口
Person person = new Person();
person.setName("Liting");
person.setAge(20);
try {
mIOnroad.introducePerson(person);
} catch (RemoteException e) {
e.printStackTrace();
}
3. 測試
將AidlServerDemo及AidlClientDemo的apk裝載到Android設(shè)備或者模擬器上跋理,運(yùn)行:得到Service端的log如下
23169-23210/tech.onroad.aidlserverdemo D/OnroadService: My name is Liting, I am 20
說明可以正常傳遞我們的自定義類型數(shù)據(jù)了择克。
上面的例子說明我們可以將client端的自定義類型參數(shù)傳遞到service端,那service端可否將其作為返回類型回傳給client端呢前普,我們可修改接口嘗試一下:
a) 修改IOnroad.aidl
Person introducePerson(inout Person person);
b) re-build service 工程
c) 在OnroadService里復(fù)寫public Person introducePerson(Person person)introducePerson()方法
@Override
public Person introducePerson(Person person) throws RemoteException {
Log.d(TAG, "My name is " + person.getName() + ", I am " + person.getAge());
Person svcPerson = new Person();
svcPerson.setName("ServicePerson");
svcPerson.setAge(0);
return svcPerson;
}
d) 將修改后的IOnroad.aidl及IOnroad.java更新到client工程
e) 在onServiceConnected()里重新調(diào)用public Person introducePerson(Person person)接口
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mIOnroad = IOnroad.Stub.asInterface(iBinder);
try {
String svcRet = mIOnroad.sayHello("Liting", 20);
Log.d("Client", "Service return " + svcRet);
} catch (RemoteException e) {
e.printStackTrace();
}
Person person = new Person();
person.setName("Liting");
person.setAge(20);
try {
Person svcPerson = mIOnroad.introducePerson(person);
Log.d("Client", "Service return: Hello " + svcPerson.getName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
d) 測試得到client端log如下:
11-09 12:36:00.566 8538-8538/tech.onroad.aidlclientdemo D/Client: Service return Hello Liting, your age is 20
11-09 12:36:00.569 8538-8538/tech.onroad.aidlclientdemo D/Client: Service return: Hello ServicePerson
說明Service端同樣可以傳遞復(fù)雜的自定義類型肚邢。
完整代碼可到我的github下載:
更多博文可訪問我的個人網(wǎng)站:www.onroad.tech
歡迎指定,共同進(jìn)步拭卿,指定郵箱:onroad_tech@163.com