我們都知道,在Android中,系統(tǒng)會(huì)為每個(gè)進(jìn)程分配對(duì)應(yīng)的內(nèi)存空間,這部分內(nèi)存是彼此間相互獨(dú)立,不可直接交互的,這樣的設(shè)計(jì)是處于安全性以及系統(tǒng)穩(wěn)定性方面考慮的,比如當(dāng)我們的App奔潰時(shí),不至于導(dǎo)致其他App無(wú)法運(yùn)行,甚至死機(jī)等情況。那么,Android中是否就無(wú)法實(shí)現(xiàn)進(jìn)程間通信呢?答案當(dāng)然是否定的。Android中進(jìn)程通信的方式有很多,比如AIDL就可以實(shí)現(xiàn)這樣子的需求。

1.AIDL
? AIDL(Android Interface Define Language)是一種IPC通信方式,我們可以利用它來(lái)定義兩個(gè)進(jìn)程相互通信的接口。他是基于Service實(shí)現(xiàn)的一種線程間通信機(jī)制。它的本質(zhì)是C/S架構(gòu)的,需要一個(gè)服務(wù)器端,一個(gè)客戶端。
2.AIDL的使用
2.1創(chuàng)建aidl
? 首先我們?cè)贏ndroidStudio中創(chuàng)建一個(gè)Andorid工程,
? 隨后添加一個(gè)module,作為aidl的服務(wù)端
? 在aidlserver中創(chuàng)建aild目錄, 同時(shí)創(chuàng)建一個(gè)aidl文件

// IMyAidlInterface.aidl
package com.yunzhou.aidlserver;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* 自己添加的方法
*/
int add(int value1, int value2);
}
? 這邊可以看到aidl的語(yǔ)法跟JAVA是一樣的,聲明了一個(gè)接口,里面定義了aidl服務(wù)器端暴露給客戶端調(diào)用的方法。
? 完成這部分操作之后還沒(méi)有結(jié)束,我們需要手動(dòng)編譯程序,生成aidl對(duì)應(yīng)的Java代碼

2.2實(shí)現(xiàn)接口,并向客戶端放開(kāi)接口
public class MyAidlService extends Service {
public MyAidlService() {
}
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new IMyAidlInterface.Stub(){
@Override
public int add(int value1, int value2) throws RemoteException {
return value1 + value2;
}
};
}
? 我們創(chuàng)建了一個(gè)service,并在service內(nèi)部聲明了一個(gè)IBinder對(duì)象,它是一個(gè)匿名實(shí)現(xiàn)的IMyAidlInterface.Stub的實(shí)例(這部分我們后面講),同時(shí)我們?cè)诎l(fā)現(xiàn)IMyAidlInterface.Stub實(shí)例實(shí)現(xiàn)了add方法,這個(gè)方法正是我們?cè)赼idl中聲明的供客戶端調(diào)用的方法。
2.3客戶端調(diào)用aidl
? 首先在客戶端跟服務(wù)器一樣,新建aidl目錄,將服務(wù)器端的aidl拷貝到客戶端,這邊特別要注意,拷貝后的客戶端的aidl文件包目錄必須與服務(wù)器端保持一致,拷貝完后同樣時(shí)編譯工程,讓客戶端也生成對(duì)應(yīng)的java文件

? 其次就是在Activity的onCreate中綁定服務(wù)
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//綁定服務(wù)成功回調(diào)
aidl = IMyAidlInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
//服務(wù)斷開(kāi)時(shí)回調(diào)
aidl = null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//do something
bindService();
}
private void bindService(){
Intent intent = new Intent();
//Android 5.0開(kāi)始,啟動(dòng)服務(wù)必須使用顯示的,不能用隱式的
intent.setComponent(new ComponentName("com.yunzhou.aidlserver", "com.yunzhou.aidlserver.MyAidlService"));
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
? 綁定完服務(wù),就是進(jìn)行調(diào)用了,具體的頁(yè)面細(xì)節(jié)這邊不做展示,就是在Activity中放了一個(gè)按鈕,點(diǎn)擊按鈕進(jìn)行遠(yuǎn)程調(diào)用
int result = aidl.add(12, 12);
Log.e(TAG, "遠(yuǎn)程回調(diào)結(jié)果:" + result);

? 可以看到,logcat打印出來(lái)結(jié)果,說(shuō)明遠(yuǎn)程調(diào)用成功了,至此aidl的整個(gè)流程就走完了。
3.AIDL可使用的參數(shù)類型
3.1基本數(shù)據(jù)類型
我們都知道Java有8中基本數(shù)據(jù)類型,分別為byte,char,short,int,long,float,double,boolean,那這8中數(shù)據(jù)類型是否都能作為aidl的參數(shù)進(jìn)行傳遞呢?我們可以在aild中嘗試下,并編譯,看看有沒(méi)有錯(cuò)
void basicTypes(byte aByte, char aChar, short aShort, int anInt, long aLong, float aFloat,
double aDouble, boolean aBoolean);
發(fā)現(xiàn)這樣子定義,無(wú)法成功編譯,經(jīng)過(guò)篩查發(fā)現(xiàn)aidl并不能支持short基本數(shù)據(jù)類型,至于為什么呢,可以看一看Android中的Parcel,Parcel是不支持short的,這應(yīng)該是考慮到兼容性問(wèn)題吧。
所以基本數(shù)據(jù)類型支持:byte,char,int,long,float,double,boolean
3.2引用數(shù)據(jù)類型
引用數(shù)據(jù)類型根據(jù)官方介紹,可以使用String,CharSequence,List,Map,當(dāng)然,我們也可以使用自定義數(shù)據(jù)類型。
3.3自定義數(shù)據(jù)類型
自定義數(shù)據(jù)類型,用于進(jìn)程間通信的話,必須實(shí)現(xiàn)Parcelable接口,Parcelable是類似于Java中的Serializable,Android中定義了Parcelable,用于進(jìn)程間數(shù)據(jù)傳遞,對(duì)傳輸數(shù)據(jù)進(jìn)行分解,編組的工作,相對(duì)于Serializable,他對(duì)于進(jìn)程間通信更加高效。
我們來(lái)看下下面的例子
public class User implements Parcelable {
private int id;
private String name;
public User() {
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
public User(Parcel in){
//注意順序?。?!注意順序?。?!注意順序?。?!
this.id = in.readInt();
this.name = in.readString();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
//注意順序?。?!注意順序!?。∽⒁忭樞颍。?!
dest.writeInt(id);
dest.writeString(name);
}
public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>(){
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
? 這邊我們定義了一個(gè)User類,實(shí)現(xiàn)了Parcelable接口,大致的類結(jié)構(gòu)就是這個(gè)樣子的,需要注意的一點(diǎn)是,Parcelable對(duì)數(shù)據(jù)進(jìn)行分解/編組的時(shí)候必須使用相同的順序,字段以什么順序分解的,編組時(shí)就以什么順序讀取數(shù)據(jù),不然會(huì)有問(wèn)題!
? 創(chuàng)建完實(shí)體后,我們需要?jiǎng)?chuàng)建一個(gè)aidl文件,來(lái)定義一下我們的User,否則User在aidl中無(wú)法識(shí)別
// IMyAidlInterface.aidl
package com.yunzhou.aidlserver;
parcelable User;
? 并在之前的服務(wù)器端aidl中新增方法
interface IMyAidlInterface {
int add(int value1, int value2);
List<User> addUser(in User user);
}
? 在service中實(shí)現(xiàn)新增的addUser方法
private ArrayList users;
@Override
public IBinder onBind(Intent intent) {
users = new ArrayList<User>();
return iBinder;
}
private IBinder iBinder = new IMyAidlInterface.Stub(){
@Override
public int add(int value1, int value2) throws RemoteException {
return value1 + value2;
}
@Override
public List<User> addUser(User user) throws RemoteException {
users.add(user);
return users;
}
};
? 此時(shí),server端的目錄就夠如下

? 服務(wù)器端一切準(zhǔn)備就緒后,我們對(duì)客戶端進(jìn)行操作,首先,我們將服務(wù)端的兩個(gè)aidl文件復(fù)制到客戶端,包結(jié)構(gòu)必須一致,aidl文件發(fā)生變化不要忘記重新編譯代碼。
? 然后,將User實(shí)體也復(fù)制到客戶端,并且包結(jié)構(gòu)一致。
? 最后,在客戶端進(jìn)行addUser的操作(這邊只是添加了一個(gè)按鈕,每點(diǎn)擊一次就調(diào)用一次addUser)
try {
ArrayList<User> users = (ArrayList<User>) aidl.addUser(new User(12, "demaxiya"));
Log.e(TAG, "遠(yuǎn)程回調(diào)結(jié)果:" + users.toString());
} catch (RemoteException e) {
e.printStackTrace();
}
? 此時(shí)客戶端的目錄結(jié)構(gòu)如下:

? 運(yùn)行服務(wù)端與客戶端App,點(diǎn)擊addUser,輸出日下日志,說(shuō)明調(diào)用成功

4.AIDL原理
? 要了解aidl原理,我們需要看一下根據(jù)aidl生成的對(duì)應(yīng)的java代碼了,
public interface IMyAidlInterface extends android.os.IInterface{
public static abstract class Stub extends android.os.Binder implements com.yunzhou.aidlserver.IMyAidlInterface{...}
public int add(int value1, int value2) throws android.os.RemoteException;
public java.util.List<com.yunzhou.aidlserver.User> addUser(com.yunzhou.aidlserver.User user) throws android.os.RemoteException;
}
? 我們可以看到,生成的代碼結(jié)構(gòu)很簡(jiǎn)單,一個(gè)靜態(tài)抽象類Stub,以及aidl中定義的方法,其中Stub肯定時(shí)核心,我們深入閱讀

? Stub的目錄結(jié)構(gòu)也不復(fù)雜,一個(gè)構(gòu)造函數(shù),一個(gè)asInterface方法,一個(gè)asBinder方法,一個(gè)onTransact方法,一個(gè)Proxy代理類,這邊Proxy與Stub同時(shí)實(shí)現(xiàn)了我們定義的aidl,且Proxy中實(shí)現(xiàn)了我們?cè)赼idl中定義的add/addUser方法。下面兩個(gè)int為告訴系統(tǒng)的方法Id
? 在客戶端,我們綁定服務(wù)的時(shí)候通過(guò)Stub.asInterface()回去aidl對(duì)象,查看asInterface源碼,我們不難發(fā)現(xiàn),客戶端獲取到的其實(shí)時(shí)Stub.Proxy,一個(gè)遠(yuǎn)程服務(wù)的代理。
//客戶端獲取aidl
aidl = IMyAidlInterface.Stub.asInterface(service);
//Stub的asInterface
public static com.yunzhou.aidlserver.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.yunzhou.aidlserver.IMyAidlInterface))) {
return ((com.yunzhou.aidlserver.IMyAidlInterface)iin);
}
return new com.yunzhou.aidlserver.IMyAidlInterface.Stub.Proxy(obj);
}
? 所以客戶端調(diào)用add/addUser方法其實(shí)調(diào)用的時(shí)Stub.Proxy中實(shí)現(xiàn)的add/addUser,在Stub.Proxy中我們可以看到一句核心代碼
//add
mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
//addUser
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
? 追溯源頭,mRemote其實(shí)就是IMyAidlInterface.Stub,隨意mRemote.transact傳遞到了IMyAidlInterface.Stub.OnTransact, onTransact中執(zhí)行了add/addUser,回調(diào)到了我們?cè)诜?wù)端定義Service中聲明IBidner時(shí)重寫(xiě)的add/addUser,這就是AIDL的整個(gè)流程。
private IBinder iBinder = new IMyAidlInterface.Stub(){
@Override
public int add(int value1, int value2) throws RemoteException {
return value1 + value2;
}
@Override
public List<User> addUser(User user) throws RemoteException {
users.add(user);
return users;
}
};
? 下面用一張圖來(lái)總結(jié)aidl原理,這邊特別感謝imooc
