一、介紹
AIDL(Android Interface Definition Language)是一種接口定義語言。
它允許你定義一個編程接口,用于約束兩個進程間的通訊規則,提供給編譯器生成代碼,實現Android設備上的兩個進程間通信(IPC)。
在Android系統中,一個進程通常不能訪問另一個進程的內存。所以他們需要將他們的對象拆解成操作系統所能識別的原語數據(primitives),然后傳入到另一個進程之后再替你組裝成對象。
也就是說進程之間的通信信息,首先會被轉換成AIDL協議消息,然后發送給對方,對方收到AIDL協議消息后再轉換成相應的對象。
由于進程之間的通信信息需要雙向轉換,所以Android采用代理類在背后實現了信息的雙向轉換,代理類由Android編譯器生成。
二、適用場景
一般適用于為其它應用程序提供公共服務的Service,這種Service即為系統常駐的Service(如:天氣服務等)。
三、優缺點
優點
1.AIDL有自己的獨立進程,不會受到其它進程的影響;
2.可以被其它進程復用,提供公共服務;
3.具有很高的靈活性。
缺點
相對普通服務,占用系統資源較多,使用AIDL進行IPC也相對麻煩。
四、具體操作(此處我們創建一個服務端程序,一個客戶端程序)
1.生成AIDL文件(服務端創建)
選擇 new->aidl->aidl file
填寫創建的名稱
會在main目錄下為你創建一個aidl文件夾,并在里面與你的包名對應創建了你的aidl文件,此文件默認會給你創建一個方法,該方法只是作為類型案例解釋,可以不需要
點擊Gradle圖標讓編譯器為我們生成對應AIDL的 類 文件
2.創建Service提供服務,AIDL涉及到IPC通信,所以需要使用綁定服務。
public class MyService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return aidl;
}
IMyAidlInterface.Stub aidl = new IMyAidlInterface.Stub(){
public static final String TAG = "AIDL";
//此處重寫所有的抽象方法,實現提供對外暴露的接口
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
Log.i(TAG,"服務正在執行...");
}
};
}
3.注冊服務
<application android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--注冊服務-->
<service android:name=".MyService"
android:process="com.my.remote.service" >
<intent-filter>
<action android:name="com.myaidl.server"/>
</intent-filter>
</service>
</application>
如果客戶端與服務端在同個App中,AndroidManifest.xml中設置Remote Service的andorid:process屬性時,如果被設置的進程名是以一個冒號(:)開頭的,則這個新的進程對于這個應用來說是私有的,當它被需要或者這個服務需要在新進程中運行的時候,這個新進程將會被創建。如果這個進程的名字是以小寫字符開頭的,則這個服務將運行在一個以這個名字命名的全局的進程中,當然前提是它有相應的權限。這將允許在不同應用中的各種組件可以共享一個進程,從而減少資源的占用。
4.拷貝服務端aidl文件到客戶端目錄下(文件夾路徑不可變化)
點擊Gradle圖標讓編譯器為我們生成對應AIDL的 類 文件
5.客戶端連接代碼
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
//服務注冊的行為
intent.setAction("com.myaidl.server");
//5.0之后 需要設置服務所在的包名(服務APP的服務所在包名)
//否則會報 IllegalArgumentException: Service Intent must be explicit
intent.setPackage("nightingale.aidl_server");
//綁定服務
bindService(intent,conn,BIND_AUTO_CREATE);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//通過我們自己定義的AIDL文件的Stub.asInterface方法 傳入服務傳遞過來的iBinder對象 返回我們的AIDL對象
IMyAidlInterface aidl = IMyAidlInterface.Stub.asInterface(iBinder);
try {
//此處方法為你在AIDL文件中,自己定義的方法 此處對應我們的AIDL文件
aidl.basicTypes(0,0,true,0,0,null);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
如果無法調用AIDL對象(自定義的IMyAidlInterface)那么需要使用Gradle 構建一下,或者檢查你是否拷貝了服務端的aidl文件到客戶端
6.安裝服務端,安裝客戶端執行結果
五、AIDL參數的傳遞(基礎數據類型 與 自定類型)
AIDL默認支持下面幾種數據類型:
Java編程語言中的基礎數據類型(int,long,char,boolean等)
String,CharSequence,List,Map,在List 中的所有元素必須是上面支持的類型或者是其他由AIDL生成的接口,或者你申明的實現了Parcelable接口的類型。
List可能被選用為泛型類,比如 List<String>.實際在接受服務一側生成的類為永遠是 ArrayList。盡管生成的方法使用的是 List接口。
Map中的雖有元素必須是上面類型或者是其他由AIDL生成的接口,或者你申明的實現了Parcelable接口的類型。泛型例如 Map<String,Integer>不支持。實際在接受服務一側生成的類為永遠是HashMap。盡管生成的方法使用的是 Map接口。
你必須要為每一個上面未列出類型添加import申明,盡管他們是作為接口定義在同一個包里面。
示例:
1.寫一個類 實現 Parcelable
public class User implements Parcelable {
private String name;
private int age;
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;
}
public User(){
}
protected User(Parcel in) {
name = in.readString();
age = in.readInt();
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(name);
parcel.writeInt(age);
}
}
2.在AIDL中定義獲取該類的方法
package nightingale.aidl_server;
//***導入對應的類,必須***
import nightingale.aidl_server.User;
interface IMyAidlInterface {
//默認的 可刪除 可不官 這里案例使用 所以 仍在這里吧
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
//獲取用戶對象
User getUser();
}
3.在aidl文件夾中聲明User對象
4.拷貝aidl中的文件到客戶端
5.拷貝服務端的User類到客戶端
注意:此處拷貝的時候,拷貝過去的類所在包名需要跟服務器所在包名一致,此處我創建了一個 aidl_server包
6.服務端Service代碼
public class MyService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return aidl;
}
IMyAidlInterface.Stub aidl = new IMyAidlInterface.Stub(){
public static final String TAG = "AIDL";
//此處重寫所有的抽象方法,實現提供對外暴露的接口
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
Log.i(TAG,"服務正在執行...");
}
@Override
public User getUser() throws RemoteException {
return null;
}
};
}
7.客戶端使用代碼
public class MainActivity extends AppCompatActivity {
private String TAG="aidl";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
//服務注冊的行為
intent.setAction("com.myaidl.server");
//5.0之后 需要設置服務所在的包名(服務APP的服務所在包名)
//否則會報 IllegalArgumentException: Service Intent must be explicit
intent.setPackage("nightingale.aidl_server");
//綁定服務
bindService(intent,conn,BIND_AUTO_CREATE);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//通過我們自己定義的AIDL文件的Stub.asInterface方法 傳入服務傳遞過來的iBinder對象 返回我們的AIDL對象
IMyAidlInterface aidl = IMyAidlInterface.Stub.asInterface(iBinder);
try {
User user = aidl.getUser();
String name = user.getName();
if(!TextUtils.isEmpty(name)){
Log.i(TAG,name);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}
執行結果
至此 AIDL的相關操作就介紹完了??,不好請吐槽!謝謝
關于Messenger的介紹,推薦閱讀:陳育 Android IPC機制(五):詳解Bundle與“信使”——Messenger:http://www.lxweimin.com/p/6e23037d6d20