綁定服務(wù):
綁定服務(wù)是客戶(hù)端-服務(wù)器接口中的服務(wù)器吮廉。綁定服務(wù)可讓組件(例如 Activity)綁定到服務(wù)递惋、發(fā)送請(qǐng)求、接收響應(yīng)佑惠,甚至執(zhí)行進(jìn)程間通信 (IPC)朋腋。 綁定服務(wù)通常只在為其他應(yīng)用組件服務(wù)時(shí)處于活動(dòng)狀態(tài),不會(huì)無(wú)限期在后臺(tái)運(yùn)行膜楷。
本文向您介紹如何創(chuàng)建綁定服務(wù)旭咽,包括如何綁定到來(lái)自其他應(yīng)用組件的服務(wù)。 不過(guò)赌厅,您還應(yīng)參閱服務(wù)文檔穷绵,了解有關(guān)一般服務(wù)的更多信息,例如:如何利用服務(wù)傳送通知特愿、如何將服務(wù)設(shè)置為在前臺(tái)運(yùn)行等等仲墨。
基礎(chǔ)知識(shí)
綁定服務(wù)是 Service類(lèi)的實(shí)現(xiàn),可讓其他應(yīng)用與其綁定和交互揍障。要提供服務(wù)綁定目养,您必須實(shí)現(xiàn) onBind()回調(diào)方法。該方法返回的 IBinder對(duì)象定義了客戶(hù)端用來(lái)與服務(wù)進(jìn)行交互的編程接口毒嫡。
客戶(hù)端可通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)癌蚁。調(diào)用時(shí),它必須提供 ServiceConnection的實(shí)現(xiàn)兜畸,后者會(huì)監(jiān)控與服務(wù)的連接努释。[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))方法會(huì)立即無(wú)值返回,但當(dāng) Android 系統(tǒng)創(chuàng)建客戶(hù)端與服務(wù)之間的連接時(shí)膳叨,會(huì)調(diào)用 ServiceConnection上的 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))洽洁,向客戶(hù)端傳遞用來(lái)與服務(wù)通信的IBinder。
多個(gè)客戶(hù)端可同時(shí)連接到一個(gè)服務(wù)菲嘴。不過(guò)饿自,只有在第一個(gè)客戶(hù)端綁定時(shí),系統(tǒng)才會(huì)調(diào)用服務(wù)的 onBind()方法來(lái)檢索 IBinder龄坪。系統(tǒng)隨后無(wú)需再次調(diào)用 onBind()昭雌,便可將同一 IBinder傳遞至任何其他綁定的客戶(hù)端。
當(dāng)最后一個(gè)客戶(hù)端取消與服務(wù)的綁定時(shí)健田,系統(tǒng)會(huì)將服務(wù)銷(xiāo)毀(除非startService()也啟動(dòng)了該服務(wù))烛卧。
當(dāng)您實(shí)現(xiàn)綁定服務(wù)時(shí),最重要的環(huán)節(jié)是定義您的 onBind()回調(diào)方法返回的接口。您可以通過(guò)幾種不同的方法定義服務(wù)的IBinder接口总放,下文對(duì)這些方法逐一做了闡述呈宇。
綁定到已啟動(dòng)服務(wù)
正如服務(wù)文檔中所述,您可以創(chuàng)建同時(shí)具有已啟動(dòng)和綁定兩種狀態(tài)的服務(wù)局雄。 也就是說(shuō)甥啄,可通過(guò)調(diào)用startService()啟動(dòng)該服務(wù),讓服務(wù)無(wú)限期運(yùn)行炬搭;此外蜈漓,還可通過(guò)調(diào)用[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))使客戶(hù)端綁定到服務(wù)。
如果您確實(shí)允許服務(wù)同時(shí)具有已啟動(dòng)和綁定狀態(tài)宫盔,則服務(wù)啟動(dòng)后融虽,系統(tǒng)“絕對(duì)不會(huì)”在所有客戶(hù)端都取消綁定時(shí)銷(xiāo)毀服務(wù)。 為此灼芭,您必須通過(guò)調(diào)用[stopSelf()](http://developer.android.com/reference/android/app/Service.html#stopSelf()或 stopService()顯式停止服務(wù)有额。
盡管您通常應(yīng)該實(shí)現(xiàn) onBind()或[onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int)),但有時(shí)需要同時(shí)實(shí)現(xiàn)這兩者姿鸿。例如谆吴,音樂(lè)播放器可能發(fā)現(xiàn)讓其服務(wù)無(wú)限期運(yùn)行并同時(shí)提供綁定很有用處。 這樣一來(lái)苛预,Activity 便可啟動(dòng)服務(wù)進(jìn)行音樂(lè)播放,即使用戶(hù)離開(kāi)應(yīng)用笋熬,音樂(lè)播放也不會(huì)停止热某。 然后,當(dāng)用戶(hù)返回應(yīng)用時(shí)胳螟,Activity 可綁定到服務(wù)昔馋,重新獲得回放控制權(quán)。
請(qǐng)務(wù)必閱讀管理綁定服務(wù)的生命周期部分糖耸,詳細(xì)了解有關(guān)添加綁定已啟動(dòng)服務(wù)時(shí)該服務(wù)的生命周期信息秘遏。
創(chuàng)建綁定服務(wù)
創(chuàng)建提供綁定的服務(wù)時(shí),您必須提供 IBinder嘉竟,用以提供客戶(hù)端用來(lái)與服務(wù)進(jìn)行交互的編程接口邦危。
您可以通過(guò)三種方法定義接口:
擴(kuò)展 Binder 類(lèi)
如果服務(wù)是供您的自有應(yīng)用專(zhuān)用,并且在與客戶(hù)端相同的進(jìn)程中運(yùn)行(常見(jiàn)情況)舍扰,則應(yīng)通過(guò)擴(kuò)展 Binder類(lèi)并從onBind()返回它的一個(gè)實(shí)例來(lái)創(chuàng)建接口倦蚪。客戶(hù)端收到Binder后边苹,可利用它直接訪(fǎng)問(wèn) Binder實(shí)現(xiàn)中乃至Service中可用的公共方法陵且。
如果服務(wù)只是您的自有應(yīng)用的后臺(tái)工作線(xiàn)程,則優(yōu)先采用這種方法个束。 不以這種方式創(chuàng)建接口的唯一原因是慕购,您的服務(wù)被其他應(yīng)用或不同的進(jìn)程占用聊疲。使用 Messenger
如需讓接口跨不同的進(jìn)程工作,則可使用 Messenger為服務(wù)創(chuàng)建接口沪悲。服務(wù)可以這種方式定義對(duì)應(yīng)于不同類(lèi)型 Message對(duì)象的 Handler售睹。此 Handler是 Messenger的基礎(chǔ),后者隨后可與客戶(hù)端分享一個(gè) IBinder可训,從而讓客戶(hù)端能利用 Message對(duì)象向服務(wù)發(fā)送命令昌妹。此外,客戶(hù)端還可定義自有Messenger握截,以便服務(wù)回傳消息飞崖。
這是執(zhí)行進(jìn)程間通信 (IPC) 的最簡(jiǎn)單方法,因?yàn)?Messenger會(huì)在單一線(xiàn)程中創(chuàng)建包含所有請(qǐng)求的隊(duì)列谨胞,這樣您就不必對(duì)服務(wù)進(jìn)行線(xiàn)程安全設(shè)計(jì)固歪。使用 AIDL
AIDL(Android 接口定義語(yǔ)言)執(zhí)行所有將對(duì)象分解成原語(yǔ)的工作,操作系統(tǒng)可以識(shí)別這些原語(yǔ)并將它們編組到各進(jìn)程中胯努,以執(zhí)行 IPC牢裳。之前采用 Messenger的方法實(shí)際上是以 AIDL 作為其底層結(jié)構(gòu)。如上所述叶沛,Messenger會(huì)在單一線(xiàn)程中創(chuàng)建包含所有客戶(hù)端請(qǐng)求的隊(duì)列蒲讯,以便服務(wù)一次接收一個(gè)請(qǐng)求。不過(guò)灰署,如果您想讓服務(wù)同時(shí)處理多個(gè)請(qǐng)求判帮,則可直接使用 AIDL。 在此情況下溉箕,您的服務(wù)必須具備多線(xiàn)程處理能力晦墙,并采用線(xiàn)程安全式設(shè)計(jì)。
如需直接使用 AIDL肴茄,您必須創(chuàng)建一個(gè)定義編程接口的 .aidl文件晌畅。Android SDK 工具利用該文件生成一個(gè)實(shí)現(xiàn)接口并處理 IPC 的抽象類(lèi),您隨后可在服務(wù)內(nèi)對(duì)其進(jìn)行擴(kuò)展寡痰。
注:大多數(shù)應(yīng)用“都不會(huì)”****使用 AIDL 來(lái)創(chuàng)建綁定服務(wù)抗楔,因?yàn)樗赡芤缶邆涠嗑€(xiàn)程處理能力,并可能導(dǎo)致實(shí)現(xiàn)的復(fù)雜性增加氓癌。因此谓谦,AIDL 并不適合大多數(shù)應(yīng)用,本文也不會(huì)闡述如何將其用于您的服務(wù)贪婉。如果您確定自己需要直接使用 AIDL反粥,請(qǐng)參閱 AIDL 文檔。
擴(kuò)展 Binder 類(lèi)
如果您的服務(wù)僅供本地應(yīng)用使用,不需要跨進(jìn)程工作才顿,則可以實(shí)現(xiàn)自有 Binder類(lèi)莫湘,讓您的客戶(hù)端通過(guò)該類(lèi)直接訪(fǎng)問(wèn)服務(wù)中的公共方法。
注:此方法只有在客戶(hù)端和服務(wù)位于同一應(yīng)用和進(jìn)程內(nèi)這一最常見(jiàn)的情況下方才有效郑气。 例如幅垮,對(duì)于需要將 Activity 綁定到在后臺(tái)播放音樂(lè)的自有服務(wù)的音樂(lè)應(yīng)用,此方法非常有效尾组。
以下是具體的設(shè)置方法:
- 在您的服務(wù)中忙芒,創(chuàng)建一個(gè)可滿(mǎn)足下列任一要求的 Binder實(shí)例:
- 包含客戶(hù)端可調(diào)用的公共方法
- 返回當(dāng)前 Service 實(shí)例,其中包含客戶(hù)端可調(diào)用的公共方法
- 或返回由服務(wù)承載的其他類(lèi)的實(shí)例讳侨,其中包含客戶(hù)端可調(diào)用的公共方法
- 從 onBind()回調(diào)方法返回此 Binder實(shí)例呵萨。
- 在客戶(hù)端中,從 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)方法接收 Binder跨跨,并使用提供的方法調(diào)用綁定服務(wù)潮峦。
注:之所以要求服務(wù)和客戶(hù)端必須在同一應(yīng)用內(nèi),是為了便于客戶(hù)端轉(zhuǎn)換返回的對(duì)象和正確調(diào)用其 API勇婴。服務(wù)和客戶(hù)端還必須在同一進(jìn)程內(nèi)忱嘹,因?yàn)榇朔椒ú粓?zhí)行任何跨進(jìn)程編組。
例如耕渴,以下這個(gè)服務(wù)可讓客戶(hù)端通過(guò) Binder實(shí)現(xiàn)訪(fǎng)問(wèn)服務(wù)中的方法:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
LocalBinder為客戶(hù)端提供 getService()方法拘悦,以檢索 LocalService的當(dāng)前實(shí)例。這樣萨螺,客戶(hù)端便可調(diào)用服務(wù)中的公共方法窄做。 例如,客戶(hù)端可調(diào)用服務(wù)中的 getRandomNumber()慰技。
點(diǎn)擊按鈕時(shí),以下這個(gè) Activity 會(huì)綁定到 LocalService并調(diào)用 getRandomNumber():
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
上例說(shuō)明了客戶(hù)端如何使用 ServiceConnection的實(shí)現(xiàn)和 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)綁定到服務(wù)组砚。下文更詳細(xì)介紹了綁定到服務(wù)的過(guò)程吻商。
注:上例并未顯式取消與服務(wù)的綁定,但所有客戶(hù)端都應(yīng)在適當(dāng)?shù)臅r(shí)間(例如當(dāng) Activity 暫停時(shí))取消綁定糟红。
如需查看更多示例代碼艾帐,請(qǐng)參閱 ApiDemos 中的 LocalService.java
類(lèi)和 LocalServiceActivities.java
類(lèi)。
使用 Messenger
如需讓服務(wù)與遠(yuǎn)程進(jìn)程通信盆偿,則可使用 Messenger為您的服務(wù)提供接口柒爸。利用此方法,您無(wú)需使用 AIDL 便可執(zhí)行進(jìn)程間通信 (IPC)事扭。
當(dāng)您需要執(zhí)行 IPC 時(shí)捎稚,為您的接口使用Messenger要比使用 AIDL 實(shí)現(xiàn)它更加簡(jiǎn)單,因?yàn)?Messenger會(huì)將所有服務(wù)調(diào)用排入隊(duì)列,而純粹的 AIDL 接口會(huì)同時(shí)向服務(wù)發(fā)送多個(gè)請(qǐng)求今野,服務(wù)隨后必須應(yīng)對(duì)多線(xiàn)程處理葡公。
對(duì)于大多數(shù)應(yīng)用,服務(wù)不需要執(zhí)行多線(xiàn)程處理条霜,因此使用 Messenger可讓服務(wù)一次處理一個(gè)調(diào)用催什。如果您的服務(wù)必須執(zhí)行多線(xiàn)程處理,則應(yīng)使用 AIDL來(lái)定義接口宰睡。
以下是 Messenger 的使用方法摘要:
- 服務(wù)實(shí)現(xiàn)一個(gè) Handler蒲凶,由其接收來(lái)自客戶(hù)端的每個(gè)調(diào)用的回調(diào)
- Handler 用于創(chuàng)建 Messenger 對(duì)象(對(duì) Handler 的引用)
- Messenger 創(chuàng)建一個(gè) IBinder,服務(wù)通過(guò) onBind() 使其返回客戶(hù)端
- 客戶(hù)端使用 IBinder 將 Messenger(引用服務(wù)的 Handler)實(shí)例化拆内,然后使用后者將 Message 對(duì)象發(fā)送給服務(wù)
- 服務(wù)在其 Handler 中(具體地講旋圆,是在 handleMessage() 方法中)接收每個(gè) Message
這樣,客戶(hù)端并沒(méi)有調(diào)用服務(wù)的“方法”矛纹。而客戶(hù)端傳遞的“消息”(Message對(duì)象)是服務(wù)在其 Handler
中接收的臂聋。
以下是一個(gè)使用 Messenger接口的簡(jiǎn)單服務(wù)示例:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
請(qǐng)注意,服務(wù)就是在 Handler的 handleMessage()方法中接收傳入的 Message或南,并根據(jù) what成員決定下一步操作孩等。
客戶(hù)端只需根據(jù)服務(wù)返回的 IBinder創(chuàng)建一個(gè) Messenger,然后利用 send()發(fā)送一條消息采够。例如肄方,以下就是一個(gè)綁定到服務(wù)并向服務(wù)傳遞 MSG_SAY_HELLO消息的簡(jiǎn)單 Activity:
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
請(qǐng)注意,此示例并未說(shuō)明服務(wù)如何對(duì)客戶(hù)端作出響應(yīng)蹬癌。如果您想讓服務(wù)作出響應(yīng)权她,則還需要在客戶(hù)端中創(chuàng)建一個(gè)Messenger。然后逝薪,當(dāng)客戶(hù)端收到 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)時(shí)隅要,會(huì)向服務(wù)發(fā)送一條 Message,并在其send()方法的 replyTo參數(shù)中包含客戶(hù)端的 Messenger董济。
如需查看如何提供雙向消息傳遞的示例步清,請(qǐng)參閱 MessengerService.java
(服務(wù))和MessengerServiceActivities.java
(客戶(hù)端)示例。
綁定到服務(wù)
應(yīng)用組件(客戶(hù)端)可通過(guò)調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)虏肾。Android 系統(tǒng)隨后調(diào)用服務(wù)的 onBind()方法廓啊,該方法返回用于與服務(wù)交互的 IBinder。
綁定是異步的封豪。[bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))會(huì)立即返回谴轮,“絕對(duì)不會(huì)”**使 IBinder返回客戶(hù)端。要接收 IBinder吹埠,客戶(hù)端必須創(chuàng)建一個(gè) ServiceConnection實(shí)例第步,并將其傳遞給 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))疮装。ServiceConnection
包括一個(gè)回調(diào)方法,系統(tǒng)通過(guò)調(diào)用它來(lái)傳遞 IBinder雌续。
注:只有 Activity斩个、服務(wù)和內(nèi)容提供程序可以綁定到服務(wù)—您無(wú)法從廣播接收器綁定到服務(wù)。
因此驯杜,要想從客戶(hù)端綁定到服務(wù)受啥,必須:
- 實(shí)現(xiàn) ServiceConnection。您的實(shí)現(xiàn)必須重寫(xiě)兩個(gè)回調(diào)方法:
- [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))
系統(tǒng)會(huì)調(diào)用該方法以傳遞服務(wù)的 onBind()方法返回的 IBinder鸽心。 -
onServiceDisconnected()
Android 系統(tǒng)會(huì)在與服務(wù)的連接意外中斷時(shí)(例如當(dāng)服務(wù)崩潰或被終止時(shí))調(diào)用該方法滚局。當(dāng)客戶(hù)端取消綁定時(shí),系統(tǒng)“絕對(duì)不會(huì)”調(diào)用該方法顽频。
調(diào)用 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))以傳遞 ServiceConnection實(shí)現(xiàn)藤肢。
當(dāng)系統(tǒng)調(diào)用您的 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))回調(diào)方法時(shí),您可以使用接口定義的方法開(kāi)始調(diào)用服務(wù)糯景。
要斷開(kāi)與服務(wù)的連接嘁圈,請(qǐng)調(diào)用 unbindService()。
當(dāng)您的客戶(hù)端被銷(xiāo)毀時(shí)蟀淮,它將取消與服務(wù)的綁定最住,但您應(yīng)該始終在完成與服務(wù)的交互時(shí)或您的 Activity 暫停時(shí)取消綁定,以便服務(wù)能夠在未被占用時(shí)關(guān)閉怠惶。 (下文更詳細(xì)地闡述了綁定和取消綁定的適當(dāng)時(shí)機(jī)涨缚。)
例如,以下代碼段通過(guò)擴(kuò)展 Binder 類(lèi)將客戶(hù)端與上面創(chuàng)建的服務(wù)相連策治,因此它只需將返回的 IBinder
轉(zhuǎn)換為L(zhǎng)ocalService類(lèi)并請(qǐng)求 LocalService實(shí)例:
LocalService mService;
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
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;
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e(TAG, "onServiceDisconnected");
mBound = false;
}
};
客戶(hù)端可通過(guò)將此 ServiceConnection傳遞至 [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務(wù)脓魏。例如:
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- [bindService()](http://developer.android.com/reference/android/content/Context.html#bindService(android.content.Intent, android.content.ServiceConnection, int))
的第一個(gè)參數(shù)是一個(gè) Intent,用于顯式命名要綁定的服務(wù)(但 Intent 可能是隱式的) - 第二個(gè)參數(shù)是 ServiceConnection對(duì)象
- 第三個(gè)參數(shù)是一個(gè)指示綁定選項(xiàng)的標(biāo)志通惫。它通常應(yīng)該是 BIND_AUTO_CREATE茂翔,以便創(chuàng)建尚未激活的服務(wù)。 其他可能的值為 BIND_DEBUG_UNBIND和 BIND_NOT_FOREGROUND履腋,或 0(表示無(wú))檩电。
附加說(shuō)明
以下是一些有關(guān)綁定到服務(wù)的重要說(shuō)明:
- 您應(yīng)該始終捕獲 DeadObjectException
異常,它們是在連接中斷時(shí)引發(fā)的府树。這是遠(yuǎn)程方法引發(fā)的唯一異常 - 對(duì)象是跨進(jìn)程計(jì)數(shù)的引用
- 您通常應(yīng)該在客戶(hù)端生命周期的匹配引入 (bring-up) 和退出 (tear-down) 時(shí)刻期間配對(duì)綁定和取消綁定。 例如:
- 如果您只需要在 Activity 可見(jiàn)時(shí)與服務(wù)交互料按,則應(yīng)在 onStart()期間綁定奄侠,在 onStop()期間取消綁定。
- 如果您希望 Activity 在后臺(tái)停止運(yùn)行狀態(tài)下仍可接收響應(yīng)载矿,則可在 onCreate()期間綁定垄潮,在onDestroy()期間取消綁定烹卒。請(qǐng)注意,這意味著您的 Activity 在其整個(gè)運(yùn)行過(guò)程中(甚至包括后臺(tái)運(yùn)行期間)都需要使用服務(wù)弯洗,因此如果服務(wù)位于其他進(jìn)程內(nèi)旅急,那么當(dāng)您提高該進(jìn)程的權(quán)重時(shí),系統(tǒng)終止該進(jìn)程的可能性會(huì)增加牡整。
注:通常情況下藐吮,切勿在 Activity 的 onResume()和 onPause()期間綁定和取消綁定,因?yàn)槊恳淮紊芷谵D(zhuǎn)換都會(huì)發(fā)生這些回調(diào)逃贝,您應(yīng)該使發(fā)生在這些轉(zhuǎn)換期間的處理保持在最低水平谣辞。此外,如果您的應(yīng)用內(nèi)的多個(gè) Activity 綁定到同一服務(wù)沐扳,并且其中兩個(gè) Activity 之間發(fā)生了轉(zhuǎn)換泥从,則如果當(dāng)前 Activity 在下一次綁定(恢復(fù)期間)之前取消綁定(暫停期間),系統(tǒng)可能會(huì)銷(xiāo)毀服務(wù)并重建服務(wù)沪摄。 (Activity文檔中介紹了這種有關(guān) Activity 如何協(xié)調(diào)其生命周期的 Activity 轉(zhuǎn)換躯嫉。)
如需查看更多顯示如何綁定到服務(wù)的示例代碼,請(qǐng)參閱 ApiDemos 中的 RemoteService.java
類(lèi)杨拐。
管理綁定服務(wù)的生命周期
當(dāng)服務(wù)與所有客戶(hù)端之間的綁定全部取消時(shí)祈餐,Android 系統(tǒng)便會(huì)銷(xiāo)毀服務(wù)(除非還使用 [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))啟動(dòng)了該服務(wù))。因此戏阅,如果您的服務(wù)是純粹的綁定服務(wù)昼弟,則無(wú)需對(duì)其生命周期進(jìn)行管理—Android 系統(tǒng)會(huì)根據(jù)它是否綁定到任何客戶(hù)端代您管理。
不過(guò)奕筐,如果您選擇實(shí)現(xiàn) [onStartCommand()](http://developer.android.com/reference/android/app/Service.html#onStartCommand(android.content.Intent, int, int))回調(diào)方法舱痘,則您必須顯式停止服務(wù),因?yàn)橄到y(tǒng)現(xiàn)在已將服務(wù)視為已啟動(dòng)离赫。在此情況下芭逝,服務(wù)將一直運(yùn)行到其通過(guò) stopSelf()自行停止,或其他組件調(diào)用 stopService()為止渊胸,無(wú)論其是否綁定到任何客戶(hù)端旬盯。
此外,如果您的服務(wù)已啟動(dòng)并接受綁定翎猛,則當(dāng)系統(tǒng)調(diào)用您的 onUnbind()方法時(shí)胖翰,如果您想在客戶(hù)端下一次綁定到服務(wù)時(shí)接收 onRebind()調(diào)用(而不是接收 onBind()調(diào)用),則可選擇返回 true切厘。onRebind()返回空值萨咳,但客戶(hù)端仍在其 [onServiceConnected()](http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected(android.content.ComponentName, android.os.IBinder))
回調(diào)中接收 IBinder。下文圖 1 說(shuō)明了這種生命周期的邏輯疫稿。
如需了解有關(guān)已啟動(dòng)服務(wù)生命周期的詳細(xì)信息培他,請(qǐng)參閱服務(wù)文檔鹃两。