前言
本文主要講述AIDL作用以及如何快速上手AIDL項(xiàng)目
簡介
A [android]
I [Interface]
D [Definition]
L [Language]
Android接口定義語言叫确。
作用:方便系統(tǒng)為我們生成代碼從而實(shí)現(xiàn)跨進(jìn)程通訊七扰,僅此而已猎贴。(玉剛老師如是說也)键痛,也就是說這個(gè)AIDL就只是一個(gè)快速跨進(jìn)程通訊的工具励稳。
快速上手
本篇文章意在快速實(shí)現(xiàn)AIDL項(xiàng)目,更多詳細(xì)內(nèi)容下篇繼續(xù)闡述。
在服務(wù)端創(chuàng)建AIDL文件降宅,用來聲明java Bean以及傳輸調(diào)用的接口∏舭裕【聲明文件】
在服務(wù)端創(chuàng)建Service并且實(shí)現(xiàn)上面的接口腰根。【創(chuàng)建服務(wù)】
客戶端綁定Service拓型《詈伲【綁定服務(wù)】
客戶端調(diào)用服務(wù)端接口×哟欤【跨進(jìn)程調(diào)用】
服務(wù)端
創(chuàng)建服務(wù)端項(xiàng)目
首先我們在app/src/main 目錄下創(chuàng)建AIDL文件夾册养。
創(chuàng)建載體MessageBean
首先我們在這個(gè)AIDL文件夾里創(chuàng)建用來傳輸?shù)膉ava Bean對象(包名并不重要),并且實(shí)現(xiàn)Parcelable接口(建議使用Parcelable插件)压固,因?yàn)檫M(jìn)程間通訊需要將該對象轉(zhuǎn)化為字節(jié)序列球拦,用于傳輸或者存儲(chǔ)。(傳遞的載體)
public class MessageBean implements Parcelable {
private String content;//需求內(nèi)容
private int level;//重要等級(jí)
``````
get set方法
``````
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.content);
dest.writeInt(this.level);
}
//如果需要支持定向tag為out,inout邓夕,就要重寫該方法
public void readFromParcel(Parcel dest) {
//注意刘莹,此處的讀值順序應(yīng)當(dāng)是和writeToParcel()方法中一致的
this.content = dest.readString();
this.level = dest.readInt();
}
protected MessageBean(Parcel in) {
this.content = in.readString();
this.level = in.readInt();
}
public MessageBean() {
public static final Creator<MessageBean> CREATOR = new Creator<MessageBean>() {
@Override
public MessageBean createFromParcel(Parcel source) {
return new MessageBean(source);
}
@Override
public MessageBean[] newArray(int size) {
return new MessageBean[size];
}
};
}
創(chuàng)建AIDL文件MessageBean.AIDL
因?yàn)锳IDL這個(gè)語言的規(guī)范就是aidl文件阎毅,所以我們必須將MessageBean轉(zhuǎn)為aidl文件焚刚,供其它aidl的調(diào)用與交互。就這么簡單扇调,一個(gè)文件里面兩行代碼矿咕。(這個(gè)文件要與java Bean放置同一包下)
package qdx.aidlserver;//手動(dòng)導(dǎo)包
parcelable MessageBean;//parcelable是小寫
文件類型:用AIDL書寫的文件的后綴是 .aidl,而不是 .java狼钮。
數(shù)據(jù)類型:AIDL默認(rèn)支持一些數(shù)據(jù)類型碳柱,在使用這些數(shù)據(jù)類型的時(shí)候是不需要導(dǎo)包的,但是除了這些類型之外的數(shù)據(jù)類型熬芜,在使用之前必須導(dǎo)包莲镣,就算目標(biāo)文件與當(dāng)前正在編寫的 .aidl 文件在同一個(gè)包下——在 Java 中,這種情況是不需要導(dǎo)包的涎拉。比如瑞侮,現(xiàn)在我們編寫了兩個(gè)文件,一個(gè)叫做 IDemandManager.java 鼓拧,另一個(gè)叫做 IDemandManager.aidl半火,它們都在 qdx.aidlserver 包下 ,現(xiàn)在我們需要在 .aidl 文件里使用 MessageBean 對象季俩,那么我們就必須在 .aidl 文件里面寫上 import qdx.aidlserver.MessageBean; 哪怕 .java 文件和 .aidl 文件就在一個(gè)包下钮糖。
默認(rèn)支持的數(shù)據(jù)類型
Java中的八種基本數(shù)據(jù)類型( byte,short(不支持short酌住,編譯不通過)店归,int阎抒,long,float娱节,double挠蛉,boolean,char)
String 和 CharSequence類型
List : List中的所有元素必須是AIDL支持的類型之一肄满,里面的每個(gè)元素都必須能夠被AIDL支持
Map : Map中的所有元素必須是AIDL支持的類型之一谴古,包括key和value
Parcelabel : 所有實(shí)現(xiàn)了Parcelabel 接口的對象
AILD : 所有的AIDL接口本身也可以在AIDL文件中使用
創(chuàng)建AIDL文件IDemandManager.AIDL
我們創(chuàng)建IDemandManager
接口用來實(shí)現(xiàn)傳遞方法。
另外方法內(nèi)如果有傳輸載體稠歉,就必須指明定向tag(in,out,inout)
in : 客戶端數(shù)據(jù)對象流向服務(wù)端掰担,并且服務(wù)端對該數(shù)據(jù)對象的修改不會(huì)影響到客戶端。
out : 數(shù)據(jù)對象由服務(wù)端流向客戶端怒炸,(客戶端傳遞的數(shù)據(jù)對象此時(shí)服務(wù)端收到的對象內(nèi)容為空带饱,服務(wù)端可以對該數(shù)據(jù)對象修改,并傳給客戶端)
-
inout : 以上兩種數(shù)據(jù)流向的結(jié)合體阅羹。(但是不建議用此tag,會(huì)增加開銷)
package qdx.aidlserver; import qdx.aidlserver.MessageBean; import qdx.aidlserver.IDemandListener; interface IDemandManager { MessageBean getDemand(); void setDemandIn(in MessageBean msg);//客戶端->服務(wù)端 //out和inout都需要重寫MessageBean的readFromParcel方法 void setDemandOut(out MessageBean msg);//服務(wù)端->客戶端 void setDemandInOut(inout MessageBean msg);//客戶端<->服務(wù)端 }
埋坑與完善
該篇文章內(nèi)容不多勺疼,但是處處皆是精華,尤其是以下3條建議捏鱼,以防引起慘案执庐。
xxx.aidl 中不能存在同方法名不同參數(shù)的方法。
xxx.aidl 中實(shí)體類必須要有指定的tag导梆。
-
在Android Studio里寫完aidl文件還需要在build.gradle文件中android{}方法內(nèi)添加aidl路徑轨淌。
sourceSets { main { java.srcDirs = ['src/main/java', 'src/main/aidl'] } }
創(chuàng)建Service
最后我們還需要?jiǎng)?chuàng)建一個(gè)服務(wù),用來處理客戶端發(fā)來的請求看尼,或者是定時(shí)推信息到客戶端递鹉。
public class AIDLService extends Service {
@Override
public IBinder onBind(Intent intent) {
return demandManager;
}
//Stub內(nèi)部繼承Binder,具有跨進(jìn)程傳輸能力
IDemandManager.Stub demandManager = new IDemandManager.Stub() {
@Override
public MessageBean getDemand() throws RemoteException {
MessageBean demand = new MessageBean("首先藏斩,看到我要敬禮", 1);
return demand;
}
@Override
public void setDemandIn(MessageBean msg) throws RemoteException {//客戶端數(shù)據(jù)流向服務(wù)端
Log.i(TAG, "程序員:" + msg.toString());
}
@Override
public void setDemandOut(MessageBean msg) throws RemoteException {//服務(wù)端數(shù)據(jù)流向客戶端
Log.i(TAG, "程序員:" + msg.toString());//msg內(nèi)容一定為空
msg.setContent("我不想聽解釋躏结,下班前把所有工作都搞好!");
msg.setLevel(5);
}
@Override
public void setDemandInOut(MessageBean msg) throws RemoteException {//數(shù)據(jù)互通
Log.i(TAG, "程序員:" + msg.toString());
msg.setContent("把用戶交互顏色都改成粉色");
msg.setLevel(3);
}
};
}
最后我們在清單文件中注冊服務(wù)
action 為服務(wù)名稱狰域,客戶端可以通過此(com.tengxun.aidl)隱式啟動(dòng)該服務(wù)媳拴。
在魅族的手機(jī)上,系統(tǒng)禁止了隱式方法啟動(dòng)服務(wù)的權(quán)限北专,所以務(wù)必在手機(jī)管家/權(quán)限管理/ 中禀挫,開啟該項(xiàng)目的自啟權(quán)限。
<service
android:name=".AIDLService"
android:exported="true">
<intent-filter>
<action android:name="com.tengxun.aidl" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>