? ? ?AIDL(android進口描述語言)是一種借口描述語言,通常應用與進程間通信。編譯根據AIDL文件生成一個系列對應的Java類,通過預先定義的接口以及Binder機制達到進程間通信的目的。其實就是一個接口,客戶端(調用者)通過bindService來與遠程服務端建立一個連接,在建立連接時會返回一個IBinder對象,該對象是服務器端Binder的BinderProxy(其實就是一個代理替身),客戶端通過asInterface函數將該BinderProxy對象包裝成本地的Proxy,并對遠程的服務端的BinderProxy對象賦值給Proxy類的mRemote字段,就是通過mRemote執行遠程函數調用。
使用AIDL實現IPC
使用AIDL實現IPC服務的步驟是:
1.創建.aidl文件-該文件(YourInterface.aidl)定義了客戶端可用的方法和數據的接口。
2.在makefile文件中加入.aidl文件-(Eclipse中的ADT插件提供管理功能)Android包括名為AIDL的編譯器,位于tools/文件夾。
3.實現接口-AIDL編譯器從AIDL接口文件中利用Java語言創建接口,該接口有一個繼承的命名為Stub的內部抽象類(并且實現了一些IPC調用的附加方法),要做的就是創建一個繼承于YourInterface.Stub的類并且實現在.aidl文件中聲明的方法。
4.向客戶端公開接口-如果是編寫服務,應該繼承Service并且重載Service.onBind(Intent)以返回實現了接口的對象實例
創建.aidl文件
AIDL使用簡單的語法來聲明接口,描述其方法以及方法的參數和返回值。這些參數和返回值可以是任何類型,甚至是其他AIDL生成的接口。重要的是必須導入所有非內置類型,哪怕是這些類型是在與接口相同的包中。下面是AIDL能支持的數據類型:
1.Java編程語言的主要類型(int, boolean等)—不需要import語句。
2.以下的類(不需要import語句):
String
List-列表中的所有元素必須是在此列出的類型,包括其他AIDL生成的接口和可打包類型。List可以像一般的類(例如List)那樣使用,另一邊接收的具體類一般是一個ArrayList,這些方法會使用List接口。
Map- Map中的所有元素必須是在此列出的類型,包括其他AIDL生成的接口和可打包類型。一般的maps(例如Map)不被支持,另一邊接收的具體類一般是一個HashMap,這些方法會使用Map接口。
CharSequence-該類是被TextView和其他控件對象使用的字符序列。
3.通常引引用方式傳遞的其他AIDL生成的接口,必須要import語句聲明
4.實現了Parcelable protocol以及按值傳遞的自定義類,必須要import語句聲明。
實例:
首先創建一個AIDL文件
package com.example.aidl;
interface?IDownload {
viod download(String ?path);
}
此時在工程里面Rebuild一下就會生成一個IDownload.java的文件生成,該類是根據IDownload.aidl文件;
其次 IDownloadService.java 類中的源碼如下:
public class IDownloadService extends Service {
private String[] URL= {"url1","url2","url3"};
private IBinder mIBinder=new DownloadBinder();
@Override
public?IBinder?onBind(Intent?intent)?{
//?TODO?Auto-generated?method?stub
return?mIBinder;
}
private class DownloadBinder extends IDownload.Stub{
@Override
public void downloade(string path) throws RemoteException {
? ? ? Log.i("DownloadBinder", path);
? ? ? ?}
}
}
從上述代碼中我們可以看出,實際上主要負責完成事務的是Stub的IDownload.Stub類,Service只是通過中間介質。
不要忘記注冊一下Service;
然后運行調用端(Server端),并且在客戶端完成Server的代碼。客戶端Activity代碼如下:
public class AIDLDemoActivity extends Activity {
private IDownload?downloadService;
/**?Called?when?the?activity?is?first?created.?*/
@Override
public?void?onCreate(Bundle?savedInstanceState)?{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent service=new Intent("com.example.aidl.downloadservice");
bindService(service,?conn,?BIND_AUTO_CREATE);
}
@Override
protected?void?onDestroy()?{
unbindService(conn);
super.onDestroy();
}
private ServiceConnection conn =new ServiceConnection() {
@Override
public?void?onServiceConnected(ComponentName?name,?IBinder?service)?{
//?TODO?Auto-generated?method?stub
downloadService = IDownload.Stub.asInterface(service);
try{
downloadService.download(url);
}cache (RemoteException e){
e.printStackTrace();
}
}
@Override
public?void?onServiceDisconnected(ComponentName?name)?{
//?TODO?Auto-generated?method?stub
downloadService =null;
}
}
}
此時運行程序時會向Server端發起連接Service請求,在連接后會將Binder對象轉換為IDownload對象,然后調用download()方法。此時download()實際上調用Server端的DownloadBinder類的實現。
到此,我們就可以了解了 Android應用中如何通過AIDL機制實現兩個進程的通訊。但是這些只是為了方便開發者很方便的去調用和完成開發;現在我們看看核心是通過AIDL文件上傳的Stub類以及背后的Binder機制。
有興趣的可以看一下生成的IDownload.java類,Stub類就是給文件的內部類,其內部實現如何轉換通信兩端的對象以及方法。
public interface IDownload extends android.os.IInterface{
public static abstract class Stub extends android.os.Binder implements com.example.aidl.downloadservice.IDownloadBinder{
.............
public Stub(){
this.attachInterface(this,DESCRIPTOR);}
}
...............
}
其實AIDL內部實現機制很復雜,其中服務端、客戶端之間還需要底層通信機制進行實現,這就是C部分,通過底層的機制進行客戶端和服務端的多次握手。
第一次使用簡書,所以文章中容易出現錯誤,如有錯誤歡迎拍鉆。