每個(gè)應(yīng)用程序都運(yùn)行在自己的進(jìn)程空間,并且可以從應(yīng)用程序UI運(yùn)行另一個(gè)服務(wù)進(jìn)程,而且經(jīng)常會(huì)在不同的進(jìn)程間傳遞對(duì)象。在Android平臺(tái),一個(gè)進(jìn)程通常不能訪問(wèn)另一個(gè)進(jìn)程的內(nèi)存空間,所以要想對(duì)話,需要將對(duì)象分解成操作系統(tǒng)可以理解的基本單元,并且有序地通過(guò)進(jìn)程邊界。
通過(guò)代碼來(lái)實(shí)現(xiàn)這個(gè)數(shù)據(jù)傳輸過(guò)程是冗長(zhǎng)乏味的,Android提供了AIDL工具來(lái)處理這項(xiàng)工作。AIDL(Android Interface Definition Language)是一種IDL 語(yǔ)言,用于生成可以在Android設(shè)備上兩個(gè)進(jìn)程之間進(jìn)行進(jìn)程間通信(IPC)的代碼。如果在一個(gè)進(jìn)程中(例如Activity)要調(diào)用另一個(gè)進(jìn)程中(例如Service)對(duì)象的操作,就可以使用AIDL生成可序列化的參數(shù)。AIDL IPC機(jī)制是面向接口的,像COM或Corba一樣,但是更加輕量級(jí)。它是使用代理類在客戶端和實(shí)現(xiàn)端傳遞數(shù)據(jù)。
一、使用AIDL實(shí)現(xiàn)IPC(Implementing IPC Using AIDL)
使用AIDL實(shí)現(xiàn)IPC服務(wù)的步驟是:第一,創(chuàng)建.aidl文件。該文件(YourInterface.aidl)定義客戶端可用的方法和數(shù)據(jù)接口。第二,在makefile文件中加入.aidl文件(Eclipse中的ADT插件提供管理功能)。Android包括名為AIDL的編譯器,位于tools/文件夾。第三,實(shí)現(xiàn)接口-AIDL編譯器從AIDL接口文件中利用Java語(yǔ)言創(chuàng)建接口。該接口有一個(gè)繼承的命名為Stub的內(nèi)部抽象類(已實(shí)現(xiàn)一些IPC調(diào)用的附加方法),要做的就是創(chuàng)建一個(gè)繼承于YourInterface.Stub的類,并且實(shí)現(xiàn)在.aidl文件中聲明的方法。第四,向客戶端公開(kāi)接口。如果是編寫服務(wù),應(yīng)該繼承Service并且重載Service.onBind(Intent)以返回實(shí)現(xiàn)了接口的對(duì)象實(shí)例。
二、創(chuàng)建.aidl文件(Create an .aidl File)
AIDL使用簡(jiǎn)單的語(yǔ)法來(lái)聲明接口,描述其方法以及方法的參數(shù)和返回值。這些參數(shù)和返回值可以是任何類型,甚至是其他AIDL生成的接口。需要注意的是,必須導(dǎo)入所有非內(nèi)置類型。AIDL能支持的數(shù)據(jù)類型有以下幾類:第一,Java編程語(yǔ)言的主要類型(int,boolean等),不需要import語(yǔ)句。第二,通常引引用方式傳遞的其他AIDL生成的接口,必須要import 語(yǔ)句聲明。第三,實(shí)現(xiàn)了Parcelable protocol 以及按值傳遞的自定義類,必須要import 語(yǔ)句聲明。另外,還有一些不需要import語(yǔ)句,如String等。
三、實(shí)現(xiàn)接口(Implementing the Interface)
AIDL生成了與.aidl文件同名的接口,如果使用Eclipse插件,AIDL會(huì)作為編譯過(guò)程的一部分自動(dòng)運(yùn)行(不需要先運(yùn)行AIDL再編譯項(xiàng)目);如果沒(méi)有插件,就要先運(yùn)行AIDL。
生成的接口包含一個(gè)名為Stub的抽象的內(nèi)部類,該類聲明了所有.aidl中描述的方法,Stub還定義了少量的輔助方法,尤其是asInterface(),通過(guò)它獲得IBinder(當(dāng)applicationContext.bindService()成功調(diào)用時(shí)傳遞到客戶端的onServiceConnected())并且返回用于調(diào)用IPC方法的接口實(shí)例。要實(shí)現(xiàn)自己的接口,就從YourInterface.Stub類繼承,然后實(shí)現(xiàn)相關(guān)方法(可以創(chuàng)建.aidl文件實(shí)現(xiàn)stub方法而不用在中間編譯,Android編譯過(guò)程會(huì)在.java文件之前處理.aidl文件)。
在完成了接口的實(shí)現(xiàn)后,需要向客戶端暴露接口,也就是發(fā)布服務(wù)。實(shí)現(xiàn)的方法是繼承 Service,然后實(shí)現(xiàn)以Service.onBind(Intent)返回一個(gè)實(shí)現(xiàn)了接口的類對(duì)象。下面的代碼片斷表示了暴露IRemoteService接口給客戶端的方式。如果有類想要能過(guò)AIDL在進(jìn)程之間傳遞,這一想法是可以實(shí)現(xiàn)的,但必須確保這個(gè)類在IPC的兩端的有效性。
以上是筆者對(duì)《Android中使用AIDL設(shè)計(jì)遠(yuǎn)程接口》的一些思路與實(shí)現(xiàn)方法。筆者認(rèn)為,由于Android自身的集成性、控制性、交互性等特點(diǎn),可以激發(fā)學(xué)生的學(xué)習(xí)的興趣,調(diào)動(dòng)學(xué)生的積極參與,擴(kuò)大學(xué)生知識(shí)面,提供多種學(xué)習(xí)的路徑。
(作者單位:鎮(zhèn)江技師學(xué)院)