一、概述
Bound Services提供了客户进程与服务进程间通信的方法
二、基础
1、服务端:实现回调方法onBind(),该方法返回IBinder对象到客户端。
2、客户端:主动调用bindService()方法与服务端绑定,绑定之后系统调用客户端的onServiceConneted()方法,客户端从该方法中得到服务端传来的IBinder。
*系统仅会在第一次客户端绑定请求的时候调用onBind(),此后的请求会自动返回同一个IBinder。
三、创建Bound Services
服务端与客户组件交互的媒介是IBinder接口。有三种方法可以定义这个接口,分别适用不同场景:
1、通过继承Binder类:适用于同程序同进程的组件间通信
这种方法的IBinder实例为Binder子类的对象,该对象有一系列公有方法,客户端可以通过IBinder媒介调用,从而与服务端通信。
实现步骤:
(1)在服务端创建Binder子类
(2)在服务端的onbind()方法中返回Binder子类实例
(3)在客户端的onServiceConnected()方法中获取该实例,这样便可以进行通信了。
服务端代码:
public class LocalService extends Service {
//传递给客户端的Binder
private final IBinder mBinder = new LocalBinder();
//随机数产生器
private final Random mGenerator = new Random();
public class LocalBinder extends Binder {
LocalService getService() {
// 返回LocalService实例,这样客户端就可以调用它的方法
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** 开放给客户端调用的方法 */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
客户端代码:
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onButtonClick(v);
}
});
}
@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) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
2、使用Messenger:适用于不同进程间通信(但服务是单线程)
实现起来比AIDL简单,有一个Messenger队列负责处理向服务端发送的message。
实现步骤:
(1)服务端创建一个Handler处理客户端发来的Message
(2)用该Handler创建一个Messenger对象
(3)通过该Messenger对象创建一个Ibinder并在onbind()中传送给客户端
(4)客户端通过该Ibinder实例化一个Message对象,并借助该Message对象与发送信息到服务端的Handler
(5)服务端在handleMessage方法中处理各种客户端发来的消息
服务端代码:
public class MessengerService extends Service {
static final int MSG_SAY_HELLO = 1;
/**
* 处理客户端发来的消息
*/
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);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
客户端代码:
public class ActivityMessenger extends Activity {
Messenger mService = null;
/** 是否绑定的标记 */
boolean mBound;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
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;
}
}
}
3、AIDL:与Messenger的差别是服务是多线程的
AIDL的相关内容将在下一篇笔记中单独列出。
四、注意
1、绑定是异步的,bindService()方法会立刻返回。
2、除broadcast receiver以外,其他组件都可以绑定到Service