Service中的绑定服务总结
綁定服務(wù)是客戶端服務(wù)器接口中的服務(wù)器,綁定服務(wù)可以讓組件綁定到服務(wù)、發(fā)送請求、接收響應(yīng),甚至執(zhí)行進程間通信IPC,綁定服務(wù)通常只在為其他應(yīng)用組件服務(wù)時處于活動狀態(tài),不會無限期在后臺運行。
綁定服務(wù)是Service類的實現(xiàn),必須實現(xiàn)onBind()回調(diào)方法,返回的IBinder對象定義了客戶端用來與服務(wù)進行交互的編程接口。客戶端通過調(diào)用bindService()綁定到服務(wù),調(diào)用時,必須提供ServiceConnection的實現(xiàn),bindService()會立即無值返回,當(dāng)系統(tǒng)創(chuàng)建客戶端與服務(wù)之間的連接時,會對ServiceConnection調(diào)用onServiceConnected(),向客戶端傳遞用來與服務(wù)通信的IBinder。
多個客戶端可以連接到一個服務(wù),只有第一個客戶端綁定服務(wù)時,系統(tǒng)才會調(diào)用onBind()來檢索IBinder,隨后無需再調(diào)用onBind(),可將同一IBinder傳遞至其他綁定的客戶端。當(dāng)最后一個客戶端取消綁定時,系統(tǒng)會將服務(wù)銷毀。實現(xiàn)綁定服務(wù)時,最重要的是定義onBind()回調(diào)方法返回接口,可以通過幾種不同方法定義服務(wù)的IBinder接口。
創(chuàng)建綁定服務(wù)
創(chuàng)建綁定服務(wù)時,必須提供IBinder,用以提供客戶端用來與服務(wù)進行交互的接口,可以通過三種方法定義接口。
擴展Binder類---若服務(wù)是該應(yīng)用專用且與客戶端相同的進程中運行,則應(yīng)通過擴展Binder類從onBind()返回一個實例來創(chuàng)建接口,客戶端收到Binder后,直接訪問Binder實現(xiàn)中乃至Service中公共方法。若服務(wù)只是自有應(yīng)用的后臺工作線程,應(yīng)優(yōu)先使用這種辦法。
使用Messenger---如需讓接口跨不同的進程工作,則可以使用Messenger為服務(wù)創(chuàng)建接口,以這種方式定義的服務(wù)可以對應(yīng)于不同類型Message對象的Handler,此Handler是Messenger的基礎(chǔ),Messenger隨后可與客戶端分享一個IBinder,從而讓客戶端利用Message對象向服務(wù)發(fā)送命令,此外,客戶端還可定義自有Messenger,以便服務(wù)回傳消息。這是執(zhí)行進程間通信IPC最簡單的方法,因為Messenger會在單一線程中創(chuàng)建包含所有請求的隊列,這樣不必對服務(wù)進行線程安全設(shè)計。
使用AIDL---Android接口定義語言,執(zhí)行所有將對象分解成原語的工作,操作系統(tǒng)可以識別這些原語并將其編組到各進程中,以執(zhí)行IPC。采用Messenger的方法實際是以AIDL作為其底層結(jié)構(gòu)。Messenger在單一線程中創(chuàng)建包含所有客戶端請求的隊列,服務(wù)一次接收一個請求。若想讓服務(wù)同時處理多個請求,則使用AIDL,此時,必須創(chuàng)建一個定義編程接口.aidl文件,AndroidSDK工具利用該文件生成一個實現(xiàn)接口并處理IPC的抽象,隨后便可以在服務(wù)內(nèi)進行擴展,注意,服務(wù)必須具備處理多線程的能力,并采用線程安全式的設(shè)計。AIDL不常用,因為比較復(fù)雜。
擴展Binder類:
若服務(wù)僅供本地應(yīng)用使用,不需要跨進程工作,則最好實現(xiàn)自有Binder類,讓客戶端通過該類直接訪問服務(wù)中的公共方法。此方法只有在客戶端和服務(wù)處于同一應(yīng)用和進程中才有效,如對于需要將Activity綁定到在后臺播放音樂的自有服務(wù)的音樂應(yīng)用。
1.創(chuàng)一個可滿足一下全部Binder實例:
包含客戶端可調(diào)用的公共方法。
返回當(dāng)前Service實例
返回由服務(wù)承載的其他類的實例
2.從onBind()回調(diào)方法返回此Binder實例。
3.在客戶端中,從onServiceConnected()回調(diào)方法接收Binder,并使用提供的方法調(diào)用綁定服務(wù)。
如,以下示例服務(wù)可讓客戶端通過Binder實現(xiàn)訪問服務(wù)中的方法:
public class LocalService extends Service {// Binder被給向客戶端private final IBinder mBinder = new LocalBinder();// 生成隨機數(shù)private final Random mGenerator = new Random();//專為客戶端使用的類,由于此服務(wù)與客戶端總是在同一進程中public class LocalBinder extends Binder {LocalService getService() {//返回this以便LocalService可以調(diào)用公共方法return LocalService.this;}}@Overridepublic IBinder onBind(Intent intent) {return mBinder;}//客戶端的方法public int getRandomNumber() {return mGenerator.nextInt(100);} }LocalBinder為客戶端提供getService()方法,以檢索LocalService的當(dāng)前實例,客戶端便可調(diào)用服務(wù)中的公共方法。點擊按鈕時,以下Activity便會綁定到LocalService并調(diào)用getRandomNumber()方法
public class BindingActivity extends Activity {LocalService mService;boolean mBound = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);}@Overrideprotected void onStart() {super.onStart();//綁定到LocalServiceIntent intent = new Intent(this, LocalService.class);bindService(intent, mConnection, Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();// 將客戶端與服務(wù)取消綁定,客戶端應(yīng)在適當(dāng)時機與服務(wù)取消綁定if (mBound) {unbindService(mConnection);mBound = false;}}//當(dāng)點擊按鈕時,調(diào)用此方法public void onButtonClick(View v) {if (mBound) {// 從LocalService調(diào)用一個方法,但是如果這個調(diào)用是可能被掛起的,那么這次請求將會放置在其他的線程中以防止Activity減緩int num = mService.getRandomNumber();Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();}}//定義綁定服務(wù)的返回值,傳至bindService()private ServiceConnection mConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName className,IBinder service) {// 已經(jīng)綁定至LocalService,轉(zhuǎn)換IBinder并獲取LocalService實例LocalBinder binder = (LocalBinder) service;mService = binder.getService();mBound = true;}@Overridepublic void onServiceDisconnected(ComponentName arg0) {mBound = false;}}; } 使用Messenger如需讓服務(wù)與遠程進程通信,可使用Messenger為服務(wù)提供接口。無需使用AIDL便可執(zhí)行進程間通信。
使用Messenger的方法:
服務(wù)實現(xiàn)一個Handler,由其接受來自客戶端的每個調(diào)用的回調(diào)。
Handler用于創(chuàng)建Messenger對象
Messenger創(chuàng)建一個IBinder,服務(wù)通過onBind()使其返回客戶端
客戶端使用IBinder將Messenger實例化,然后使用Messenger將Message對象發(fā)給服務(wù)
這樣客戶端沒有調(diào)用服務(wù)的“方法”,客戶端傳遞的“消息”(Message對象)是服務(wù)在Handler中接收的。
如下:
public class MessengerService extends Service {//要求服務(wù)顯示一個message對象static final int MSG_SAY_HELLO = 1;//來自客戶端message的Handlerclass IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_SAY_HELLO:Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();break;default:super.handleMessage(msg);}}}//給客戶端發(fā)送message到IncomingHandlerfinal Messenger mMessenger = new Messenger(new IncomingHandler());//當(dāng)綁定到服務(wù),返回一個接口到messenger,用于發(fā)送message對象到服務(wù)@Overridepublic IBinder onBind(Intent intent) {Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();return mMessenger.getBinder();} }服務(wù)就是在Handler的handleMessage()方法中接受傳入的Message,并根據(jù)what成員決定下一步操作。客戶端只需根據(jù)服務(wù)返回IBinder創(chuàng)建一個Messenger,然后利用send()發(fā)送消息。
public class ActivityMessenger extends Activity {//聲明與服務(wù)聯(lián)系的MessengerMessenger mService = null;//標(biāo)記是否已經(jīng)綁定到服務(wù)boolean mBound;//與服務(wù)的主接口相互作用的類private ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className, IBinder service) {//當(dāng)服務(wù)的連接已經(jīng)被建立時,給出可以與服務(wù)連接的對象,使用Messenger與服務(wù)聯(lián)系,所以得到一個從客戶端IBinder對象的代表、mService = new Messenger(service);mBound = true;}public void onServiceDisconnected(ComponentName className) {// 當(dāng)與服務(wù)的連接意外斷開時調(diào)用,即線程崩潰mService = null;mBound = false;}};public void sayHello(View v) {if (!mBound) return;//創(chuàng)建并發(fā)送一個’what‘值的message到服務(wù)Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);try {mService.send(msg);} catch (RemoteException e) {e.printStackTrace();}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);}@Overrideprotected void onStart() {super.onStart();//與服務(wù)綁定bindService(new Intent(this, MessengerService.class), mConnection,Context.BIND_AUTO_CREATE);}@Overrideprotected void onStop() {super.onStop();//與服務(wù)取消綁定if (mBound) {unbindService(mConnection);mBound = false;}} }若想服務(wù)對客戶端做出響應(yīng),還需在客戶端中創(chuàng)建一個Messenger,然后當(dāng)客戶端收到onServiceConnected()回調(diào)時,想服務(wù)發(fā)送一條Message,并在其send()方法的replyTo參數(shù)中包含客戶端的Messenger綁定到服務(wù)
客戶端可以通過調(diào)用bindService()綁定到服務(wù),Android系統(tǒng)隨后調(diào)用服務(wù)的onBind()方法,用于返回用于與服務(wù)交互的IBinder。綁定是異步的,bindService()會立即返回,不會使IBinder返回客戶端,要接收IBinder,客戶端必須創(chuàng)建一個ServiceConnection實例,并將其傳遞給bindService,ServiceConnection包括一個回調(diào)方法,系統(tǒng)通過該方法來傳遞IBinder。
注,只有Activity、Service和內(nèi)容提供程序可以綁定到服務(wù),Broadcast不能綁定到服務(wù)
故,若想從客戶端綁定到服務(wù),必須滿足以下條件:
1.實現(xiàn)ServiceConnection,必須重寫兩個回調(diào)方法
onServiceConnected()---系統(tǒng)會調(diào)用該方法以傳遞服務(wù)的onBind()方法返回的IBinder
onServiceDisconnected()---Android系統(tǒng)會在與服務(wù)連接意外中斷時(服務(wù)崩潰或終止時)調(diào)用該方法,當(dāng)客戶端取消綁定時,系統(tǒng)不會調(diào)用該方法。
2.調(diào)用bindService(),傳遞ServiceConnection實現(xiàn)。
3.當(dāng)系統(tǒng)調(diào)用onServiceConnected()回調(diào)方法時,可以使用接口定義的方法開始調(diào)用服務(wù)
4.調(diào)用unbindService()斷開與服務(wù)的連接。最好是在客戶端與服務(wù)交互完成后立即取消綁定客戶端,這樣可以關(guān)閉空閑服務(wù)。
以下例子通過擴展Binder類將客戶端與服務(wù)相連,只需將返回的IBinder轉(zhuǎn)換成LocalService類并請求LocalService實例:
LocalService mService; private ServiceConnection mConnection = new ServiceConnection() {//當(dāng)與服務(wù)的連接被建立時調(diào)用public void onServiceConnected(ComponentName className, IBinder service) {// 由于已經(jīng)與確定的本地線程中的服務(wù)綁定,能將其IBinder轉(zhuǎn)換為具體類并直接訪問LocalBinder binder = (LocalBinder) service;mService = binder.getService();mBound = true;}//當(dāng)與服務(wù)的連接意外斷開時調(diào)用public void onServiceDisconnected(ComponentName className) {Log.e(TAG, "onServiceDisconnected");mBound = false;} };客戶端可通過將ServiceConnection傳遞至bindService()綁定到服務(wù): Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE);bindService()第一個參數(shù)是Intent,用于顯示命名要綁定的服務(wù),第二個參數(shù)是ServiceConnection對象,第三個參數(shù)是一個指示綁定選項的標(biāo)志,通常應(yīng)該是BIND_AUTO_CREATE,以便創(chuàng)建尚未激活的服務(wù)。還可以是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND或0需要注意
應(yīng)該始終捕獲DeadObjectException異常,是在連接中斷時引發(fā)的,是遠程方法引發(fā)的唯一異常。
對象是跨進程計數(shù)的引用
通常應(yīng)該在客戶端生命周期的匹配引入和退出時刻配對綁定和解除綁定。一般Activity的onCreate()和onDestroy(),或者onCreate()和onDestroy()期間綁定和取消綁定,切勿在onResume()和onPause()綁定。
管理綁定服務(wù)的聲明周期
如果服務(wù)是純粹的綁定服務(wù),無需對其生命周期進行管理。如果選擇實現(xiàn)onStartCommand()回調(diào)方法,必須顯示停止服務(wù),服務(wù)將會一直運行到stopSelf()停止,或其他組件調(diào)用stopService()停止,無論其是否綁定到任何客戶端。若服務(wù)已經(jīng)啟動且接受綁定,則系統(tǒng)調(diào)用onUnbind()方法時,若想在客戶端下次綁定到服務(wù)時接受onRebind()調(diào)用,則選擇返回true。onRebind()返回空值,但客戶端仍在其返回onServiceConnected()回調(diào)中接收IBinder。
總結(jié)
以上是生活随笔為你收集整理的Service中的绑定服务总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android服务部分总结
- 下一篇: JDBC详解及总结