Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Interface Definition Language (AIDL)

Android Interface Definition Language (AIDL)

編輯:關於Android編程

Android Interface Definition Language (AIDL)
IN THIS DOCUMENT
Defining an AIDL Interface
Create the .aidl file
Implement the interface
Expose the interface to clients
Passing Objects over IPC
Calling an IPC Method
SEE ALSO
Bound Services
AIDL (Android Interface Definition Language) 與其他的接口定義語言相似。定義這個接口,client 和service 可以通過這個接口在進程之間進行通信。所以說,對象要能在進程之間傳遞,就需要將對象分解成系統能識別的指令。通過代碼實現那個是非常的冗長乏味的,android 系統通過AIDL可以處理。

Note: 希望從不同的應用中訪問service,並且在service需要處理多線程,這種情況下才會使用AIDL。如果不需要從其他的應用中處理IPC,那麼可以實現Binder;如果需要IPC,但是不需要處理多線程,那麼可以使用Messenger。在使用之前,先考慮好哪種方式是適合自己的。

設計AIDL接口之前,需要確認AIDL接口裡面該有的方法。不能假設當調用發生時,thread會伴隨。發生什麼是不同的,取決於該調用是從本地進程或遠程進程的線程發起的。具體來講:


在本地進程中的同一個線程發起調用請求。如果這是你的主UI線程,線程繼續在AIDL接口上執行。如果是其他的線程,它會在service中運行代碼。如果僅僅是本地線程訪問service,可以控制具體的線程在service中執行(如果是在這種情況下,不需要使用AIDL,可以用Binder方式代替).
從遠程進程的線程池中發起調用。需要准備好處理不知線程的同時發起的調用。換句話說,實現AIDL必須保證所有線程的安全性。
The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous.
Defining an AIDL Interface

--------------------------------------------------------------------------------

可以用Java編程語言的語法定義AIDL接口,文件保存在源代碼(src/)下,當前應用擁有這個service並且,其他的應用可以綁定這個service。

當構建的應用中含有.aidl文件,Android SDK 工具根據.aidl文件能夠生成一個IBinder的接口,保存在項目的gen/目錄。service應該合理的實現IBinder接口。client 應用可以綁定這個service,並通過IBinder調用service的方法。

用AIDL創建一個綁定的service,基本步驟如下:

創建.aidl文件
這個文件定義了接口和方法.

實現接口
Android SDK 工具基於.aidl文件能夠生成一個接口。接口裡面含有一個名字為Stub的抽象內部類,並且實現了AIDL接口中定義的方法。使用的時候,必須繼承Stub類,實現它的方法。

公開接口
實現service,重寫onBind(), 它的返回值是stub類。

Caution: 對AIDL接口做的任何改變,必須向後兼容,避免其他使用service的應用無法繼續工作。也就是說,因為這個.aidl文件必須復制到其他的應用中,為了能訪問這個service的接口,必須保證對原始接口的支持。

1. 創建.aidl文件
AIDL 使用簡單的語法定義接口,可以有一個或者多個方法,這些方法可以傳入參數和返回值。參數和返回值可以是任何類型,甚至其他aidl生成的接口。

.aidl文件必須使用java語法,每一個.aidl文件只能定義一個單獨的接口,並且只需要接口的聲明和方法的聲明。

一般情況,AIDL支持一下數據類型:

所有的java基本類型 (例如 int, long, char, boolean, 等等)
String
CharSequence
List
List中所有的元素必須是AIDL支持的類型,或者是其他的AIDL接口和定義的parcebles.一個List可以被用來作為一個通常類(例如,List<String>). 實際具體的類接到總是一個ArrayList,雖然該方法生成的時候是List 接口.

Map
Map中所有的元素必須是AIDL支持的類型,或者是其他的AIDL接口和定義的parcebles.通常的Map(例如Map<String,Integer>這種形式的Map是不支持的)。實際具體的類接到總是一個HashMap,雖然該方法生成的時候是Map 接口.

當要導入的類型,上面沒有列舉,需要import, 即使它們定義在和當前AIDL文件相同的包裡面。

當定義service的接口時,要意識到:

方法可以有0個或者多個參數,可以返回一個值或者是void.
All non-primitive parameters require a directional tag indicating which way the data goes. Either in, out, orinout (see the example below).
Primitives are in by default, and cannot be otherwise.

Caution: 必須考慮真正需要的數據方向,因為數據裝換是非常昂貴的。

包含在.aidl中所有的注釋在IBinder接口中都會生成(除了在import和package之前的注釋)
僅僅支持方法,不支持靜態的成員變量。
下面上.aidl 文件的例子:

// IRemoteService.aidl
package com.example.android;

// Declare any non-default types here with import statements

/** Example service interface */
interface IRemoteService {
    /** Request the process ID of this service, to do evil things with it. */
    int getPid();

    /** Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}將.aidl文件保存在 src/ 目錄下,當編譯項目的時候,, SDK tools 生成IBinder接口文件,放在項目的gen/ 目錄裡面.

如果您使用的是Eclipse,會迅速的生成Binder類。如果您沒有使用Eclipse,Ant tool 可以在下次構建應用的時候,自動生成binder 類-構建項目的時候需要ant debug (或者ant release), 在寫好.aidl文件的時候就構建一個次,以便在編碼的時候可以引用生成的類。

2. 實現接口
當您構建項目的時候,Android SDK 工具會生成一個java 接口文件。 生成的接口文件中包含一個Stub 的內部抽象類,這個類實現在.aidl中定義的方法。

Note: Stub 同樣定義了一些幫組的方法,最特別的是 asInterface(), 它需要一個IBinder(通常傳遞給客戶的onServiceConnected()回調方法), 並且返回一個stub接口的實例。See the section Calling an IPC Method for more details on how to make this cast.

要實現從.aidl文件中生成出來的接口,繼承生成的Binder接口(例如,YourInterface.Stub),並且實現從.aidl文件中繼承來的方法。

這裡是一個通過匿名類的方式實現IRemoteService 接口的例子:

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
    public int getPid(){
        return Process.myPid();
    }
    public void basicTypes(int anInt, long aLong, boolean aBoolean,
        float aFloat, double aDouble, String aString) {
        // Does nothing
    }
};現在mBinder是Stub類的一個實例,下一步,這個接口需要暴露給client調用。

這裡是實現AIDL接口的一些規則:

不能保證是從主線程裡發起的調用,因此在使用的時候,需要考慮多線程啟動和保證service運行時的線程安全性。
默認情況,遠程調用是同步的。如果你知道你的service完成的任務需要一些時間,不能從activity的主線程中調用service,因為這樣調用會導致application掛起(應用等待響應),最好在一個新的線程中調用。
Service不會返回任何開發者自己拋出的異常到調用者。
3. 把接口公開給客戶端
一旦service實現了接口,然後要把它暴露給client,以便clients綁定它。為service公開接口,繼承Service和實現onBind()並返回實現Stub類的實例.下面的service例子公開IRemoteService 接口給clients.

public class RemoteService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        // Return the interface
        return mBinder;
    }

    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
        public int getPid(){
            return Process.myPid();
        }
        public void basicTypes(int anInt, long aLong, boolean aBoolean,
            float aFloat, double aDouble, String aString) {
            // Does nothing
        }
    };
}現在,當client調用bindService()綁定service,Client通過onServiceConnected()回調函數獲得service onBind()方法的mBinder實例。

client可以訪問接口類,如果client和service在不同的application中,那麼client應用必須拷貝.aidl文件到自己的src/目錄下。(生成 android.os.Binder 接口—提供給client訪問AIDL 方法).

當client從 onServiceConnected() 中獲取到IBinder對象,就需要調用YourServiceInterface.Stub.asInterface(service) ,將返回的參數轉換成自己的ServiceInterface . 例如:

IRemoteService mIRemoteService;
private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established
    public void onServiceConnected(ComponentName className, IBinder service) {
        // Following the example above for an AIDL interface,
        // this gets an instance of the IRemoteInterface, which we can use to call on the service
        mIRemoteService = IRemoteService.Stub.asInterface(service);
    }

    // Called when the connection with the service disconnects unexpectedly
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "Service has unexpectedly disconnected");
        mIRemoteService = null;
    }
};

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved