简介
Bound Service是客户端-服务器模式的Service。Bound Service允许组件(Activity,Service,Content Provider,广播不能绑定服务)对其进行绑定、发送请求、接收响应、甚至进行进程间通信(interprocess communication IPC)。 Bound Service一般只在为其它应用程序组件服务期间才是存活的,而不会一直在后台保持运行。
Bound Service是 Service 类的一种实现,它允许其它应用程序与其绑定并交互。为了让服务支持绑定,你必须实现 onBind(Intent)
回调方法。这个方法返回一个 IBinder 对象,该对象定义了客户端与服务进行交互时所需的编程接口。客户端可以通过调用bindService()
方法来绑定服务。
Bound Service绑定过程
应用程序组件(客户端)可以通过调用 bindService()
方法来绑定服务,系统会调用服务的 onBind(Intent)
回调方法,返回一个用于和服务进行交互的 IBinder 对象。绑定是异步进行的。 bindService() 将立即返回,并不会立即向客户端返回 IBinder 。为了接收 IBinder对象,客户端必须创建一个ServiceConnection 的实例,并把它传给 bindService() 。ServiceConnection 包含了一个回调方法,系统将会调用该方法来传递客户端所需的那个 IBinder 。
注
- 只有activity、服务和content provider才可以绑定到服务上——广播接收器(broadcast receiver)不能绑定服务。
Bound Service绑定过程如下:
- 自定义一个Service继承Service类(当然需要在AndroidManifest.xml中注册),并重写
onBind(Intent)
方法,此方法中需要返回IBinder对象。 - 在组件中自定义一个ServiceConnection(ServiceConnection是一个接口)接口对象实现
onServiceConnected(ComponentName, IBinder)
方法(调用该方法来处理服务的onBind()
方法返回的 IBinder 对象)和onServiceDisconnected
方法(当与服务的绑定发生意外中断时,比如服务崩溃或者被杀死时,系统将会调用该方法,客户端解除绑定时,不会调用该方法)。 - 通过bindService (Intent, ServiceConnection, int)方法将Service绑定到组件上。int值为选择绑定的方式,系统提供。
- 通过获取的IBinder对象实现进程间通信(IPC)。
- 当客户端在恰当的生命周期时,此时需要解绑之前已经绑定的Service,通过调用
unbindService(ServiceConnection)
方法。当客户端被销毁时,与服务的绑定也将解除。但与服务交互完毕后,或者你的activity进入pause状态时,你都应该确保解除绑定,以便服务能够在用完后及时关闭。 - 多个客户端可以同时绑定到一个服务上。不过,只有在第一个客户端绑定时,系统才会调用服务的
onBind()
方法来获取 IBinder 对象。然后,系统会向后续请求绑定的客户端传送这同一个 IBinder对象,而不再调用onBind()
方法。当最后一个客户端解除绑定后,系统会销毁服务(除非服务先通过startService()
启动的,且绑定时不再调用onCreate()
方法)。
下面具体分解以上步骤
自定义一个Service类
在自定义Service类中根据onBind(Intent)
方法返回的对象,分为三种通信方式:
- Extending the Binder class
继承Binder类。如果服务是应用程序私有的,并且与客户端运行于同一个进程中(通常都是如此,也就是本地通信),那么直接通过扩展 Binder 类(继承了IBinder类)来创建一个IBinder实例,并从onBind()
返回一个它的实例。客户端通过该 Binder 对象获取Service实例并处理业务功能。如果服务只是为该应用程序执行一些后台工作,那这就是首选的技术方案。若服务要被其它应用程序使用或者要跨多个进程使用,则这种方式不行。 - Using a Messenger
使用Messenger。
- Using AIDL
使用AIDL。Android接口定义语言AIDL(Android Interface Definition Language) 可以用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。完成以下的所有工作:将对象解析为操作系统可识别的原始形态,并将它们跨进程序列化(marshal)以完成IPC。 前一个使用 Messenger 的方式,实际上也是基于AIDL的,它用AIDL作为底层结构。如上所述, Messenger 将在一个单独的进程中创建一个包含了所有客户端请求的队列,这样服务每次就只会收到一个请求(即不支持并发处理)。 可是,如果想让你的服务能同时处理多个请求,那你就可以直接使用AIDL。 这种情况下,你的服务必须拥有多线程处理能力,并且是以线程安全的方式编写的。要直接使用AIDL,你必须创建一个.aidl文件,其中定义了编程的接口。 Android SDK 工具使用此文件来生成一个抽象类(abstract class),其中实现了接口及对IPC的处理,然后你就可以在自己的服务中扩展该类。注意: 绝大多数应用程序都不应该用AIDL来创建Bound Service,因为这可能需要多线程处理能力并且会让代码变得更为复杂。 因此,AIDL对绝大多数应用程序都不适用。是否如此???
扩展Binder类
根据官方文档中的示例代码修改代码如下:
package com.sywyg.servicetest;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import java.util.Random;
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.
* 在同一进程中通信,并非IPC
*/
public class LocalBinder extends Binder {
/**
* 通过该方法获取LocalService对象
*/
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
Log.d("result","getService executed");
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d("result","onBind...");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("result","onUnbind...");
return super.onUnbind(intent);
}
/**
* method for clients
* 模拟客户端需要处理的方法
*/
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
对应activity中的代码如下:
package com.sywyg.servicetest;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binding);
}
@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