綁定服務是客戶端-服務器接口中的服務器。綁定服務可讓組件(例如 Activity)綁定到服務、發送請求、接收響應,甚至執行進程間通信 (IPC)。 綁定服務通常只在為其他應用組件服務時處于活動狀態,不會無限期在后臺運行。
綁定服務是 Service類的實現,可讓其他應用與其綁定和交互。要提供服務綁定,您必須實現 onBind()回調方法。該方法返回的 IBinder
對象定義了客戶端用來與服務進行交互的編程接口。
public class LocalService extends Service {
private IBinder mBind=new LocalBinder();
/**
* 返回的 IBinder 對象定義了客戶端用來與服務進行交互的編程接口
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBind;
}
/**
* LocalBinder 為客戶端提供 getService() 方法,以檢索 LocalService 的當前實例
*/
public class LocalBinder extends Binder{
LocalService getService(){
return LocalService.this;
}
}
public void getLog(){
Log.d("TAG", "getLog: 我是LocalService的log");
}
}
客戶端可通過調用 [bindService()](https://developer.android.com/reference/android/content/Context.html?hl=zh-cn#bindService(android.content.Intent, android.content.ServiceConnection, int))綁定到服務。調用時,它必須提供 ServiceConnection的實現,后者會監控與服務的連接。[bindService()](https://developer.android.com/reference/android/content/Context.html?hl=zh-cn#bindService(android.content.Intent, android.content.ServiceConnection, int))方法會立即無值返回,但當 Android 系統創建客戶端與服務之間的連接時,會對 ServiceConnection
調用 [onServiceConnected()](https://developer.android.com/reference/android/content/ServiceConnection.html?hl=zh-cn#onServiceConnected(android.content.ComponentName, android.os.IBinder)),向客戶端傳遞用來與服務通信的 IBinder。
public class MainActivity extends AppCompatActivity {
LocalService service;
boolean mBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
LocalService.LocalBinder binder = (LocalService.LocalBinder) iBinder;
service = binder.getService();
service.getLog();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
使用 Messenger
與 AIDL 比較
當您需要執行 IPC 時,為您的接口使用Messenger要比使用 AIDL 實現它更加簡單,因為 Messenger會將所有服務調用排入隊列,而純粹的 AIDL 接口會同時向服務發送多個請求,服務隨后必須應對多線程處理。
對于大多數應用,服務不需要執行多線程處理,因此使用 Messenger可讓服務一次處理一個調用。如果您的服務必須執行多線程處理,則應使用 AIDL 來定義接口。
如需讓服務與遠程進程通信,則可使用 Messenger 為您的服務提供接口。利用此方法,您無需使用 AIDL 便可執行進程間通信 (IPC)。
服務實現一個 Handler,由其接收來自客戶端的每個調用的回調
-
Messenger創建一個 IBinder,服務通過 onBind()使其返回客戶端
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()); /** * 綁定到服務時,我們返回一個接口給我們的messenger為服務發送消息。 */ @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }
messenger類方法
public IBinder getBinder() {
return mTarget.asBinder();
}
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
客戶端只需根據服務返回的IBInder創建一個 Messenger,然后利用 send()發送一條消息。
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;
}
}
}
管理綁定服務的生命周期
當服務與所有客戶端之間的綁定全部取消時,Android 系統便會銷毀服務(除非還使用 [onStartCommand()](https://developer.android.com/reference/android/app/Service.html?hl=zh-cn#onStartCommand(android.content.Intent, int, int))啟動了該服務)。因此,如果您的服務是純粹的綁定服務,則無需對其生命周期進行管理 — Android 系統會根據它是否綁定到任何客戶端代您管理。
不過,如果您選擇實現 [onStartCommand()](https://developer.android.com/reference/android/app/Service.html?hl=zh-cn#onStartCommand(android.content.Intent, int, int))回調方法,則您必須顯式停止服務,因為系統現在已將服務視為已啟動。在此情況下,服務將一直運行到其通過 stopSelf()自行停止,或其他組件調用 stopService()為止,無論其是否綁定到任何客戶端。
此外,如果您的服務已啟動并接受綁定,則當系統調用您的 onUnbind()方法時,如果您想在客戶端下一次綁定到服務時接收 onRebind()調用,則可選擇返回 true。onRebind() 返回空值,但客戶端仍在其 [onServiceConnected()](https://developer.android.com/reference/android/content/ServiceConnection.html?hl=zh-cn#onServiceConnected(android.content.ComponentName, android.os.IBinder))
回調中接收 IBinder。