綁定到一個Service
應用組件(客戶端)可以調用bindService()綁定到一個service.Android系統之后調用service的onBind()方法,它返回一個用來與service交互的IBinder.
綁定是異步的.bindService()會立即返回,它不會返回IBinder給客戶端.要接收IBinder,客戶端必須創建一個ServiceConnection的實例並傳給bindService().ServiceConnection包含一個回調方法,系統調用這個方法來傳遞要返回的IBinder.
注:只有activities,services,和contentproviders可以綁定到一個service—你不能從一個broadcastreceiver綁定到service.
所以,從你的客戶端綁定到一個service,你必須:
-
1實現ServiceConnection.
你的實現必須重寫兩個回調方法:
-
onServiceConnected()
系統調用這個來傳送在service的onBind()中返回的IBinder.
-
OnServiceDisconnected()
Android系統在同service的連接意外丟失時調用這個.比如當service崩潰了或被強殺了.當客戶端解除綁定時,這個方法不會被調用.
-
-
2調用bindService(),傳給它ServiceConnection的實現.
-
3當系統調用你的onServiceConnected()方法時,你就可以使用接口定義的方法們開始調用service了.
-
4要與service斷開連接,調用unbindService().
當你的客戶端被銷毀,它將從service解除綁定,但是你必須總是在你完成與service的交互時或當你的activity暫停於是service在不被使用時可以關閉此兩種情況下解除綁定.(下面會討論更多在適當的時候綁定和解除綁定的問題.)
例如,下面是前一篇"派生Binder類"中創建的代碼片段,它把客戶端連接到了service.所有需要做的就是把返回的IBinder強制轉換到LocalBinder類並且請求LocalService實例:
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() { // 當與service的連接建立后被調用 public void onServiceConnected(ComponentName className, IBinder service) { // Because we have bound to an explicit // service that is running in our own process, we can // cast its IBinder to a concrete class and directly access it. LocalBinder binder = (LocalBinder) service; mService = binder.getService(); mBound = true; } // 當與service的連接意外斷開時被調用 public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); mBound = false; } };
使用這個ServiceConnection,客戶端可以綁定到一個service,通過把它傳給bindService().例如:
Intentintent = new Intent(this, LocalService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE);
-
第一個bindService()的參數是一個明確指定了要綁定的service的Intent.
-
第二個參數是ServiceConnection對象.
-
第三個參數是一個標志,它表明綁定中的操作.它一般應是BIND_AUTO_CREATE,這樣就會在service不存在時創建一個.其它可選的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定時設為0即可.
補充事項
下面是一些關於綁定到service的重要事項:
-
你總是需要捕獲DeadObjectException異常.它會在連接被打斷時拋出.這是被遠程方法拋出的唯一異常.
-
對象引用計數是跨進程的作用的.
-
你應該在客戶端的生命期內使綁定和解除綁定配對進行,例如:
-
如果你需要在你的activity可見時與service交互,你應該在onStart()綁定並在onStop()中解除綁定.
-
如果你想讓你的activity即使在它停止時也能接收回應,那么你可以在onCreate()中綁定並在onDestroy()中解除綁定.注意這意味着你的activity需要使用在自己整個運行期間使用service(即使位於后台),所以如果service在另一個進程中,那么你增加了這個進程的負擔而使它變得更容易被系統殺掉.
-
注:你一般不應該在你的activity的onResume()和onPause()中綁定和解除綁定到service,因為這些回調方法,出現在每個生命期變化中,並且你需要使發生在這些變化中的處理最小化.還有,如果你應用中的多個activity綁定到同一個service,並且有一個變化發生在其中兩個activity之間,service可能在當前activity解除綁定(pause中)和下一個綁定前(rusume中)被銷毀又重建.
管理BoundService的生命期
當一個service的所有客戶端都解除綁定,Android系統就銷毀它(除非它是從onStartCommand()啟動).如果你的service是一個純boundservice,你不需管理它的生命期—Android系統會為你管理它.
然而,如果你選擇了實現onStartCommand()回調方法,那么你必須明確地停止service,因為service現在被認為是"開始的".在此情況下,service會一直運行,直到service使用stopSelf()停止它自己或另外的組件調用了stopService()停止了它,不管是否有客戶端綁定了它.
另外,如果你的service已經啟動並且接受綁定,那么當系統調用你的onUnbind()方法,你可以選擇返回true表示你想在客戶端下一次綁定到service時接受一個對onRebind()的調用(而不是一個對onBind()的調用).onRebind()返回void,但是客戶端依然會在它的onServiceConnected()回調中接收到IBinder.下圖演示了這種生命其的邏輯:
圖1.一個已開始並已綁定的service的生命期