Creating a Bound Service
綁定Service的作用:
一個綁定的service(bound service)是客戶端-服務器接口中的服務器。
綁定的service允許組件(比如activity)通過調用bindService()
方法和其進行綁定,建立一個長期存在的連接關系,發送請求,接收回應,甚至執行跨進程的通信(interprocess communication (IPC))。
當你需要從應用中的activity或者其他組件和service進行交互的時候,或者當你需要把應用中的一些功能通過跨進程的通信interprocess communication (IPC)暴露給其他的應用時,你應該建立一個綁定的service。
綁定Service的一般性實現:
一個綁定的service是 Service類的一個實現,允許其他的組件和其進行綁定並交互。
為了創建一個綁定的service,你必須做的第一件事是定義一個接口,指定客戶如何和這個service進行交互。
這個接口必須是IBinder接口的一個實現,並且是你的 onBind()回調方法返回的東西。
所以,為了提供綁定,你首先必須實現onBind()回調方法,這個方法返回一個IBinder
對象。
其他組件可以調用bindService()方法來取得這個接口,然后就可以開始調用service中的方法。
具體來說,一個客戶端通過bindService()
方法和service進行綁定。當客戶端這樣做的時候,它必須提供一個ServiceConnection的實現,用來監聽和service之間的連接。
bindService()方法會立即返回,當Android系統創建了客戶端和service之間的連接時,系統會調用ServiceConnection中的 onServiceConnected()
,來傳遞 IBinder
對象,讓客戶端用來和service通信。
多個客戶端綁定與生命周期的結束行為:
一個service可以同時和多個客戶端進行連接。
但是,系統僅在第一次連接的時候調用service的onBind()
方法來獲取IBinder對象。
系統會將同一個IBinder對象傳遞給其他后來增加的客戶端,不再調用onBind() 方法。
當一個客戶完成和service之間的互動后,它調用 unbindService() 方法來解除綁定。
當所有的客戶端都和service解除綁定后,系統會銷毀service。(除非service也被startService()方法開啟)。
因為,通常情況下,一個綁定的service僅當它為其他組件服務時存在,所以當沒有任何組件和其綁定時,系統會銷毀它,不會在后台無限運行。你不需要去停止一個綁定的service。
有很多方法來實現一個綁定的service,這個實現比開啟的service要復雜。下面介紹三種方法。
Creating a Bound Service
當創建一個提供綁定的service時,你必須提供給一個IBinder,來提供客戶和service交互的接口。
有三種方法可以定義這個接口:
1.繼承Binder類
如果你的service是你的應用所私有的,並且和客戶端在同一個進程中運行,你應該通過繼承Binder 類來創建接口,在 onBind()
方法中返回它的實例。
客戶端接收到這個Binder對象,並且可以直接使用它來訪問一些Binder甚至service中的public方法。
當你的service僅僅是你的應用中的一個后台工作者時,這種方法是被推薦的。
不使用這種方法創建接口的唯一理由就是你的service需要被其他應用使用,或者需要跨進程使用。
2.使用一個Messenger
如果你需要你的接口跨進程使用,你可以使用 Messenger來創建接口。
用這種方式,service定義一個 Handler用來響應不同類型的 Message 對象。
這個Handler是 Messenger和客戶分享一個 IBinder
的基礎,讓客戶端可以使用Message 對象向service發送命令。
另外,客戶端也可以定義自己的Messenger,這樣service就可以發送信息給客戶端。
這是執行跨進程通信(interprocess communication (IPC))的最簡單的方法,因為Messenger
把所有的請求排列進一個單獨的線程,所以你在設計service時不用為了線程安全而做特殊的設計。
3.使用AIDL
AIDL (Android Interface Definition Language)執行分解對象的工作,它把對象分解成primitives,操作系統可以理解並將這些primitives跨進程分組(marshall)來執行IPC。
前面使用Messenger的方法底層結構實際上是基於AIDL的。
上面提到,Messenger在一個單獨的線程中創建一個所有客戶端請求的隊列,所以service一次只接收一個請求。
然而,如果你想要你的service同時處理多個請求,那么你可以直接使用AIDL。
這種情況下,你的service必須能夠處理多線程並且是線程安全的。
要直接使用AIDL,你必須創建一個.aidl文件,定義編程接口。Android SDK使用這個文件來生成抽象類,實現接口和處理IPC,你可以在你的service中繼承它。
注意:多數應用不應該使用AIDL去創建一個bound service,因為它需要多線程,會導致一個復雜得多的實現。如果你確定要使用,可以查看 AIDL文檔。
參考資料
API Guides:Services
http://developer.android.com/guide/components/services.html
API Guides:Bound Services
http://developer.android.com/guide/components/bound-services.html