Bound Service
一个bound service是客户端服务的接口,一个绑定服务允许组件(像Activities)与服务绑定,发送请求,接收回复,并且可以实现进程间通信(IPC)。一个绑定服务典型的工作状态是它服务于其他应用程序组件,并且不是在后台无限期运行。
一个bound service 是 Service的实现类,允许其他应用程序与之绑定和交互。为了给服务提供绑定,你必须实现onBind()回调方法,这个方法返回IBinder对象,此对象是客户端可以用来和服务交互的程序接口。
一个客户端与服务绑定通过调用bindService()方法.因而,客户端必须提供一个可以监控客户端与服务器端连接的ServiceConnection的实现。
这个bindService()在调用时会立即返回,只有当安卓系统创建了客户端与服务器端的连接后,会调用ServiceConnection中的onServiceConnected()方法,以用来传递可以用来达成客户端与服务器端通信的IBinder对象
多客户端可以立即与服务器连接,然而,系统仅仅在第一个客户端与之绑定时调用你的服务中的onBind()方法取回IBinder,系统会传递相同的IBinder给追加绑定的客户端,而不会再去调用onBind()方法
当所有客户端与服务解绑,系统会销毁这个服务(除非你的服务是通过startService()来启动的)
当你实现你的bound service时,最重要的部分是定义你onBind()回调方法返回的接口。下面有几种不同的方法你可以定义你的服务中的IBinder接口。
创建一个Bound Service
当创建一个提供绑定的服务时,你必须提供一个客户端可以用来与服务交互的的程序接口——IBinder。下面有三种方式你可以定义这个接口
继承一个Binder类
如果你的服务是你自己程序专用的,并且和客户端在同一个进程中运行,你应该通过继承Binder类来创建你的接口,并且在onBind()方法中返回一个它的实例对象。客户端接收到这个Binder并且可以使用它去直接访问Binder实现类和Service中的公有方法。
当你的服务仅仅在后台为自己的应用工作,那么这将是首选的技术。
使用Messenger
如果你需要你的接口在不同进程中工作,你可通过Messenger创建一个服务接口。在这种方式总,服务定义一个可以回应不用类型的Message对象的Handler,这个Handle是一个Messenger的组成部分与客户端共享一个IBinder,允许客户端通过Message对象给服务发送一些命令。客户端可以定义一个自己的Messenger 因此服务可以发送消息回执。
这是实现ipc最简单的方式,Messenger将所有请求按队列组织在一个单线程中,所以不用去考虑线程安全问题
使用aidl
aidl是 android interface definition language ,aidl将对象分解为操作系统可以理解的原语,并且引领他们跨越进程去执行ipc,上面提到的使用了Messenger的技术,是基于aidl的,就像上面所说的,Messenger创建了一个队列将所有请求安置于一个线程中个,因此服务一次只能接收一个请求,如果你希望你的服务同时处理多个请求,你可以直接使用AIDL.在这种情况下,你的服务必须能够保证多线程执行和线程安全
为了使用aidl,你需要去创建一个定义了程序接口.aidl文件,android sdk 会使用这个文件去生成一个实现了这个接口并且处理ipc的抽象类。
接下来为大家具体介绍这三种方式的代码实现
一、继承Binder类
如果你的服务仅仅在本地应用使用,而且不需要进程间传递,你可以实现一个自己的Binder类,以实现客户端对服务端公有方法的直接访问。.
Note: The reason the service and client must be in the sameapplication is so the client can cast the returned object and properly call its APIs. The serviceand client must also be in the same process, because this technique does not perform anymarshalling across processes.
主要分成三步(1)在你的服务中创建一个Binder的实例
(2)在onBind()回调方法中返回这个Binder实例
(3)在客户端中,从onServiceConnected()回调方法中接收这个Binder对象并且使用它调用bound service中提供的公有方法
public class LocalService extends Service {
// 为客户端提供的Binder对象
private final IBinder mBinder = new LocalBinder();
// 随机数生成器
private final Random mGenerator = new Random();
/**
* Binder的实现类
*/
public class LocalBinder extends Binder {
LocalService getService() {
// 返回一个外部类对象的实例,客户端可以通过这个方法调用一些公有方法
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** 给客户端提供的方法 */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
这个LocalBinder给客户端提供了getService()方法去取回当前LocalService的实例。这使得客户端可以调用服务中的方法。比如说,客户端可以调用服务中的getRadnomNumber()方法
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();
// 与LocalService绑定
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;
}
}
/** 按钮的单击事件方法 */
public void onButtonClick(View v) {
if (mBound) {
// 调用一个LocalService中的方法
// 如果调用这些方法会占用时间,应该放置于分支线程中处理,以避免对主线程的阻塞
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
//监控与服务之间的连接
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// 转换Ibinder为LocalBinder对象,并且获取到一个LocalService的实例
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
二、使用Mennenger
如果你需要你的服务区与远程的进程通信,你可以使用一个Messenger去为你的服务提供接口。这项技术允许你去实现进程间通信,而不需要使用AIDL
这是一下使用Messenger的摘要
- 这个服务实现了一个接收来自的客户端每次调用的回调的Handler
- 这个Handler是用来去创建一个Messenger对象
- 这个Messenger创建了一个通过onBind()方法从服务发送到客户IBinder
- 客户端使用IBinder通实例化这个可以给服务端发送Message的Messenger对象
- The service receives each
Message
in itsHandler
—specifically, in thehandleMessage()
method. - 服务端在Handler中接收每个Message,在handleMessage()中来处理。
这种方式中,没有任何服务端“方法”在客户端中被调用,而是 客户端发送“messages”,服务端在其Handler中接收。
public class MessengerService extends Service {
/** 自己定义的消息的标记 */
static final int MSG_SAY_HELLO = 1;
/**
* 处理客户端传来的消息的Handler
*/
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);
}
}
}
/**
* 发送给客户端可以传递Messenger给Handler的Messenger对象
*/
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();
}
}
Handler实现中的handleMessage()方法,是服务端接收客户端传递来的信息并对消息作出反应的地方。
所有的客户端需要去创建一个基于服务器中返回的IBinder对象的Messenger对象,并且调用send()方法发送message
public class ActivityMessenger extends Activity {
/** 与服务器端交互的Messenger */
Messenger mService = null;
/** 服务是否绑定的指示器 */
boolean mBound;
/**
* 与服务器端主接口进行交互的类
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
/*当客户端与服务器之间的连接建立好了这个方法就会被调用,给我们一个IBinder实例创建 Messenger对象*/
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
//连接出现问题时调用
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
//创建并且发送一个message给服务端
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();
//绑定服务
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// 解绑服务
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}