Service和AIDL

Service是android中實現程序後臺運行的解決方案,它非常適合用於去執行那些不需要和用戶交互而且還要長期運行的任務。Service默認並不會運行在子線程中,它也不運行在一個獨立的進程中,他同樣執行在UI線程中,因此不要在Service中執行耗時的操作,除非你在Service中創建了子線程來完成耗時操作。當某個應用程序進程被殺死時,所有依賴於該進程的Service也會停止運行。
服務啓動了之後會一直保持運行狀態,直到stopService或stopSelf函數被調用。IntentService將用戶的請求執行在一個子線程中,用戶只需要覆寫onHandleIntent函數,並且在該函數中完成自己耗時的操作即可。在任務執行完畢之後IntentSerivce會調用stopSelf自我銷燬,因此它適用於完成一些短期的耗時任務。
如果希望Service可以一直保持運行狀態,而不會由於系統內存不足被回收,可以將Service運行在前臺,前臺服務不僅不會被系統無情的回收,它還會在通知欄顯示一條消息。調用startForeground將服務設置爲前臺服務。
AIDL是一種接口描述語言,通常用於進程間通信。編譯器根據AIDL文件生成一個系列對應的java類,通過預先定義的接口以及Binder機制達到進程間通信的目的。客戶端通過bindService來與遠程服務端建立一個連接,在該連接建立時會返回一個IBinder對象,該對象是服務端Binder的BinderProxy,在建立連接時,客戶端通過asInterface函數將該BinderProxy對象包裝成本地的Proxy,並將遠程服務端的BinderProxy對象賦值給Proxy類的mRemote字段,就是通過mRemote執行遠程函數調用。
AIDL的用法如下:
在客戶端新建一個ADIL文件,添加一個void ssoAuth(String username, String pwd)函數,Rebuild下工程就會生成一個SsoAuth.java類,同時將該AIDL文件拷貝到服務端,它們的包名、類名完全一致。生成的類也完全一致,這樣在遠程調用時它們就能夠擁有一致的類型,該文件中有一個Stub類實現了SsoAuth接口。
我們首先需要定義一個Service子類,然後再定義一個繼承自Stub的子類,並且在Service的onBind函數中返回這個Stub子類的對象。實際上完成功能的是繼承自Stub的SinaSsoImpl類。服務註冊運行起來。客戶端進行服務綁定bindService,服務連接後在onServiceConnected函數中將Binder轉換爲SsoAuth,mSsoAuth = SsoAuth.Stub.asInterface(iBinder),最後調用mSsoAuth.ssoAuth。實際上是調用服務端的SinaSsoImpl的ssoAuth函數。
這一切的核心都是通過AIDL文件生成的Stub類以及其背後的Binder機制。在SsoAuth.java中最重要的是生成一個Stub類,該類繼承自Binder類,並且實現類SsoAuth接口。Stub裏面最重要的就是asInterface()函數,在這個函數中會判斷obj參數的類型,如果obj是本地類型,則認爲不是進程間調用,否則會通過自動生成另一個內部類Proxy來包裝obj,將obj賦值給Proxy中的mRemote字段。Proxy類也實現了SsoAuth接口,不同的是它是通過Binder機制來與遠程進程進行交互。
客戶端的調用會通過Binder機制傳遞到服務端,最終調用Stub類中的onTransact函數,服務端是指令的接收端。我們調用ssoAuth()時,實際上就是通過mRemote向服務端提交了一個TRANSACTION_ssoAuth請求。客戶端綁定成功連接後,onServiceConnected(ComponentName name, IBinder service)這裏的service對象是BinderProxy類型,通過asInterface轉換後被包裝成了Proxy類型,但是調用的時候,執行的是服務端SinaSsoImpl中的ssoAuth函數,因此SinaSsoImpl實例mBinder被服務端包裝成BinderProxy類型,再經過客戶端的Proxy進行包裝,通過Binder機制進行數據傳輸,實現進程間調用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章