1、绑定式Service在cs结构中扮演着Service的角色,绑定式Service允许其他组件绑定该Service、发送请求、接收相应、甚至IPC通信,绑定式Service通常服务于其他应用程序的组件,且没有明确的后台概念。
2、绑定式Service基础
绑定式Service是一个继承于Service的类,他可以与其他应用交互,为了实现绑定Service,你必须重写onBind()方法,该方法返回一个IBind()借口,此接口是绑定式Service与其他应用组件交互的桥梁。
其他组件可调用bindService()绑定Service,该方法需要传入的参数包含一个实现了ServiceConnection的对象,该对象监控着组件与Service的绑定状态,bindService()并不返回数据,而一旦系统创建了组件与Service的连接,ServiceConnection借口中的方法onServiceConnected()方法会被调用,此时实现了IBinder接口的对象将传递至组件中,这样便实现了Service与绑定组件的通信。
Service可以同时与多个组件绑定,然而Service仅在绑定的第一个组件回调onBind()方法以获得IBinder对象,之后与该Service绑定的组件都传递同一个IBinder对象而不调用onBind()方法。
当Service与绑定他的最后一个组件解绑时,系统将该Service销毁,当然若该Service用start的方法启动过,则不会被销毁。
创建bound Service时,最重要的是实现onBind()方法中的返回接口IBinder,下面将介绍几种不同实现IBinder接口的实现方式。
3、如何实现IBinder接口的方式
(1)继承Binder类:Binder是一个实现了IBinder接口的类,若Service只允许被本应用所在的进程访问(这是大多数情况),你需要继承Binder类,并将给对象作为onBind()方法的返回值,这样与Service绑定的组件就可以通过该返回对象访问Binder的继承类的public方法,甚至是Service中的方法。若在你的应用程序中,Service仅作为一个在后台工作的组件,那么这种方式在好不过了,除非你需要Service进行跨进程通信
(2)使用Messenger:如果需要使用IBinder进行跨进程通信,你应当为Service创建一个Messager对象,这样Service可以定义一个Handler对象以接受不同类型的Message。Handler是Messager的基础,他可以在客户端与IBinder共享,并允许使用Message对象向Service发送指令,除此之外,也可以在client端定义Messenger,这样Service端可以回传信息。
(3)使用AIDL:AIDL是Android接口语言的缩写,大多数应用程序不应该使用AIDL创建bound Service,因为这需要应用程序有处理多线程的能力,而这会使应用程序变得复杂。
4、继承Binder类
若你的Service仅是应用程序内部使用,那么可以继承Binder类,这样,与Service绑定的组件可以直接访问Service中的public方法
请注意:这种继承Binder类的方式仅适用于Service与绑定的组件处在同一个应用程序的情况下。
创建方式:
1)在Service类中创建一个继承于Binder的内部类,在Service类中定义public方法,以便cilent端可以访问,在继承于Binder的内部类中返回该Service实例,将该内部类实例作为onBind()的返回参数。
2)在客户端中的onServiceConnection()回调方法中接收Binder对象,并访问Service的public方法
public class LocalService extends Service {
//传递给客户端的Binder
private final IBinder mBinder = new LocalBinder();
//随机数生成器
private final Random mGenerator = new Random();
/**
* 客户端绑定类,因为我们知道服务总是和绑定的组件运行在同一进程中,我们不需要处理跨进程通信
*/
public IBinder onBind(Intent intent) {
return mBinder;
}
public class LocalBinder extends Binder {
LocalService getService() {
//返回一个实例以便我们能够调用服务的方法
return LocalService.this;
}
}
public int getRandomNumber() {
return mGenerator.nextInt();
}
}
在上例中,LocalBinder提供getService()方法来获取LocalService实例,这样客户端就可以通过该实例访问Service中的方法,如下所示
public class MainActivity extends AppCompatActivity {
LocalService mService;
boolean mBound = false;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button=new Button(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int num = mService.getRandomNumber();
Log.i("onCreate: ", num + "");
}
});
setContentView(button);
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
首先,在Activity中的onStart()回调中调用bindService()绑定LocalService(),这时,LocalService中的onCreate()与onBind() 依此回调,接着,ServiceConnection中的onServiceConnection()方法回调,表示组件与Service已经绑定,这时可以通过回传给onServiceConnection()中的IBinder接口对象获得Service的实例,一旦获得该实例,便可以调用Service中的public方法。
请注意:Service应该在合适的时候与组件解除绑定,本例在onStop()中解除绑定
5、使用Messenger绑定Service
当Service需要进行IPC通信时,应当在Service中使用Messenger。使用Messenger方法如下:
1)继承Handle类,并实现回调方法handleMessage()方法,每当cilent端访问Service中的方法时,handleMessager()方法都将回调。
2)需要在Service中创建一个Messenger对象,构造该对象需传入一个Handle参数
3)调用Messenger的getBind()返回一个IBinder对象,将该对象作为onBind()的返回值
4)client端通过onServiceConnection()回传的IBinder参数,构造Messenger对象,并将Message信息传入Messenger对象,发送给Service
5)Service在Handle的handleMessage()方法中接收Message信息
按照这种方式,client并没有显式调用Service中的方法,而是传递Message对象,并在Service中的Hnadle中接收。
以下是Service端示例:
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();
default:
super.handleMessage(msg);
}
}
}
final Messenger mMessenger=new Messenger(new inComingHandler());
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
client客户端
public class ActivityMessenger extends Activity {
//用来和Service交流的Messenger;
Messenger mService = null;
//来表明我们是否绑定了Service
boolean mBound = false;
//主页面和服务的交互类
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = new Messenger(service);
mBound = true;
Toast.makeText(ActivityMessenger.this, "success", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
mBound = false;
}
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
Button button = new Button(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mBound){
Toast.makeText(ActivityMessenger.this, "fail", Toast.LENGTH_SHORT).show();
return;
}
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (Exception e) {
Toast.makeText(ActivityMessenger.this,e.toString(), Toast.LENGTH_SHORT).show();
}
}
});
setContentView(button);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
} <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">定Service。</span>
所以,绑定Service有以下步骤:
1)实现ServiceConnection接口:
实现onServiceConnected()方法,当client与Service建立绑定时,系统回调该方法,并将onBind()返回的IBinder参数回传至该方法中
实现onServiceDisconnected()方法,当绑定的Service意外终止时,回调该方法,如进程被kill或者Service崩溃,系统若回调unBindService(),将不会回调onServiceDisconnected()方法。
2)调用bindService,并传入ServiceConnection的实现类对象
3)当系统回调onServiceConnection()时,表示client与Service绑定,此时可以访问Service中的public方法
4)系统回调unbindService(),接触绑定
请注意:当client与Service绑定时,系统destory掉client端,这将破坏绑定状态,好的做法是只要client与Service的交互完成,就解除绑定
其中第三个参数表示绑定的模式,通常为BIND_AUTO_CREATE,表示当Service还尚未处于alive的状态时创建该Service,其他可用参数为BIND_DEBUG_UNBIND,BIND_NOT_FOREGROUND,若不打算制定模式,可传入0
7、需要额外注意的地方
1)当连接错误时,系统会抛出DeadObjectException异常,这也是client端调用Service中的方法时唯一可能抛出的异常。
2)bind和unbind应该成对调用
3)当Activity在前台处于运行状态时,需要与Service绑定,那么应在onStart()中bindService(),在onStop()中unbindService()
4)当Activity在后台处于onStop状态时,那么应该在onCreate()中bindService(),在onDestory()unbindService()
5)不要在onResume()和onPause()方法中绑定、解绑Service,因为这两个生命周期经常被回调,频繁的绑定解绑会降低程序效率
8、管理绑定Service的生命周期
当Service不再与其他任何client绑定时,系统将回收该Service,你无需手动管理,系统会自动管理
若通过两种方式同时启动一个Service,那么如果希望在下一次启动Service绑定client回调onRebind()方法,应该在onUnbind()方法中返回true,按照这种方式,再次与该Service绑定的client仍可以在onServiceConnented()接收到回传的IBinder参数,如下图所示: