Android AIDL - 進程間的通訊接口

AIDL = Android Interface Definition Language

進程之間如何通訊呢? 

在Windows系統中存在IPC管道服務、消息等方法。在Java中,由於不允許跨進程記憶體共用,因此傳遞物件,只能把物件拆分成作業系統能理解的簡單形式,以達到跨界物件訪問的目的。因此J2EE採用RMI的方式,可以通過序列化傳遞物件。


而Android則採用所謂的AIDL接口定義語言。AIDL能夠建立一個interface(aidl檔),編譯器可根據aidl檔生成一段代碼,通過預先定義的介面讓不同process之間進行資訊的傳遞(e.g. IPC)。Client Process可以藉由Bind Service Process來取得資訊。



如何使用AIDL? (以Eclipse開發為例)

AIDL的跨進程(IPC)的遠距溝通機制和COM或CORBA類似,是基於介面的。它使用代理類在用戶端和實現層間傳遞值。步驟如下:


1. 創建aidl文件。這個文件定義了一個接口(XXX.aidl),該介面定義了可供用戶端訪問的方法和屬性。


NOTE:理論上,參數可以傳遞基底資料型別和String,還有Bundle的派生類。不過在Eclipse中,目前的ADT不支援Bundle做為參數。[來源:AIDL --- Android中的遠程接口, 2010.7]

    ex: src/IHelloServiceBinder.aidl

    package [your package name]
    interface IHelloServiceBinder {
        String getServiceName();
    }

2. 在Java檔中實現你的接口方法。編譯器會根據AIDL介面, 產生一個Java介面,這這個介面有一個名為Stub的內部抽象類別,它繼承擴展了介面並實現了遠端調用需要的幾個方法。

經過"Build Project"之後,gen/目錄下會自動產生對應的 .java檔,此interface檔案中包含了一個名為Stub的subclass (a binder)。 ex: IHelloServiceBinder.java


3. 暴露你的接口給客戶端。AIDL介面的實現,在Service中以內嵌類的方式實作interface,並且在onBind()回傳該interface。

    ex: src/HelloService.java
    
    public class HelloService extends Service {
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }

        private final IHelloServiceBinder.Stub mBinder
                = new IHelloServiceBinder.Stub() {
            // Implement AIDL Interface
            @Override
            public String getServiceName() 
                    throws RemoteException {
                return "HelloService";
            }
        };
    }

    AndroidManifest.xml

    <application
        ...
        <service
            android:name=".HelloService"
            android:process=":remote" />
        ...
    </application>


4. 在Client端進行遠端調用。Client process在bind service之後 (待service回傳IBinder之後) 即可對service提供的method進行操作。

NOTE: aidl檔在client和service的src/目錄下都要存在一份(複製過去即可),雙方才知道此interface [來源:Android AIDL的使用, 2012.12]

    public class MainActivity extends Activity {
        IHelloServiceBinder mIHelloServiceBinder;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        
            // Bind Service
            Intent intent
                    = new Intent(this, HelloService.class);
            bindService(intent,
                   mConnection, Context.BIND_AUTO_CREATE);
        }
    
        private ServiceConnection mConnection
                = new ServiceConnection() {
            public void onServiceConnected(ComponentName
                    className, IBinder service) {
                // Get an instance of IHelloServiceBinder
                mIHelloServiceBinder = IHelloServiceBinder.
                        Stub.asInterface(service);
                try {
                    Log.d("AIDL Test", mIHelloServiceBinder.
                            getServiceName());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            // Called when the connection
            // with the service disconnects unexpectedly
            public void onServiceDisconnected(
                    ComponentName className) {
                mIHelloServiceBinder = null;
            }
        };
    }

留言