首先描述下我們想要實現的內容,我們希望在一個應用中通過點擊按鈕,去操作另一個進程中應用的音樂播放功能。
如圖,我們點擊“播放”時,系統就會去遠程調用我們提供的一個service(與當前service不是同一個應用哦),然後操作service中的音樂播放,點擊“停止”則會終止播放。想要重新播放的話,必須先點“銷燬service”,再點播放按鈕哦。(至於這裏爲什麼要先點銷燬按鈕才能播放,完全是爲了給大家展示下,遠程調用service時,怎麼去解綁service)。
在這個例子中,我們用到了一個非常重要的概念,AIDL。
AIDL(android interface definition language)android接口描述語言,其主要的作用就是允許我們在不同的進程間進行通信。
我們都知道每個應用程序都運行在各自的進程中,並且android平臺是不允許不同進程間進行直接的對象數據等傳遞的。如果我們非要進行進程間的通訊,那麼我們就必須將我們的數據對象分解成一個個微小的、可以被操作系統理解的數據單元,然後有序的通過進程邊界的檢查。
如果讓我們自己實現,那麼這個過程都愁死一批批的程序人了。幸好android,爲我們解決了這個問題,這就是AIDL出現的原因了。
AIDL (Android Interface Definition Language)是一種IDL 語言,用於生成可以在Android設備上兩個進程之間進行進程間通信(IPC)的代碼。如果在一個進程中(例如Activity)要調用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。
AIDL IPC機制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。
注意:AIDL只支持方法,不能定義靜態成員,並且方法也不能有類似public等的修飾符;AIDL運行方法有任何類型的參數和返回值,在java的類型中,以下的類型使用時不需要導入包(import),基本數據類型、String、Map、List.當然爲了避免出錯,建議只要使用了,就導入包。
-------------------------------------------------------------------------------
使用AIDL的步驟:
服務端(提供服務):
第一步:定義一個*.aidl文件,該文件裏是符合aidl語言規範的接口定義,裏面定義了外部應用可以訪問的方法。當我們保存該文件的時候,eclipse會自動爲我們在gen文件夾下生成一個相應的java接口文件。例如RemoteServiceInterface.java
第二步:定義一個自己的service, 並將其註冊到androidManifest.xml文件中,例如:
<service android:name="MyRemoteService">
<intent-filter>
<action android:name="cn.com.chenzheng_java.remote"/>
</intent-filter>
</service>
注意這裏一定要提供一個intent-filter,我們的客戶端進程就是通過該action訪問到服務端進程的哦。
我們都知道,在實現自己的service時,爲了其他應用可以通過bindService來和我們的service進行交互,我們都要實現service中的onBind()方法,並且返回一個繼承了Binder的內部類;在這裏,eclipse自動爲我們生成的RemoteServiceInterface.java中有一個實現了Binder的內部類,RemoteServiceInterface.Stub。AIDL要求我們,在這裏不能再直接去實現Binder類了,而是去實現,AIDL提供給我們的Stub類。 實現stub類的同時,AIDL還要求我們同時實現我們在接口中定義的各種服務的具體實現。至此爲止,我們的服務端已經和我們的aidl文件綁定到一起了哦。
客戶端:
第一步:客戶端要想使用該服務,肯定要先知道我們的服務在aidl文件中到底對外提供了什麼服務,對吧?所以,第一步,我們要做的就是,將aidl文件拷貝一份到客戶端的程序中(這裏一定要注意,包路徑要和服務端的保持一致哦,例如服務端爲cn.com.chenzheng_java.remote.a.aidl,那麼在客戶端這邊也應該是這個路徑)。
第二步:我們都知道,想要和service交互,我們要通過bindService方法,該方法中有一個ServiceConnection類型的參數。而我們的主要代碼便是在該接口的實現中。
第三步:在ServiceConnection實現類的onServiceConnected(ComponentName name, IBinder service)方法中通過類似remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);方式就可以獲得遠程服務端提供的服務的實例,然後我們就可以通過remoteServiceInterface 對象調用接口中提供的方法進行交互了。(這裏的關鍵是通過*.Stub.asInterface(service);方法獲取一個aidl接口的實例哦)
我們前面在服務端中說過了,必須提供一個intent-filter來匹配請求是否合法,所以我們在客戶端訪問服務的時候,還必須傳遞包含了匹配action的Intent哦。
--------------------------------------------------------------------------------------
下邊整體是代碼:
遠程服務端:
RemoteServiceInterface.aidl
MyRemoteService.java
RemoteServiceActivity.java
androidManifest.xml
客戶端:
activity代碼:
music.xml
其他沒有粘貼出來的代碼都是由系統默認生成的。