转载请注明出处:http://blog.csdn.net/zhouli_csdn/article/details/45498809
Bound Services
绑定服务允许组件绑定到服务,发送请求,接收结果,甚至进程间通信。绑定服务仅仅存活于服务于其它组件的时候,它不会长期在后台运行。
The basics
为了提供绑定服务,你必须实现onBind方法,这个方法返回一个IBinder,定义了交互的接口。你必须实现ServiceConnection类,监控服服务的连接。bindService方法并不会立刻返回一个值,但是当系统建立了client和service的连接时,它会调用ServiceConnection的onServiceConnected方法,并且传递IBinder。多个clients可以绑定到一个服务,但是只有第一个client调用onBind方法时,才会调用onBind方法,以后就不会调用了。当最后一个client调用unBind方法时,系统会杀死这个服务(除非也调用startService)。
Creating a Bound Service
你必须提供一个IBinder,三种方法:
继承Binder类:
如果你的service对于你的应用是私有的,并且在同一个进程中运行,你可以实现该类,并通过onBind方法返回该类的一个实例。这时,client就可以访问IBinder和Service中的public方法。
如果你的服务被其它应用使用或者运行在单独的进程中,你不能使用这种方法。
Using a Messenger:
如果你需要一个接口工作于不同的进程,你可以为service创建一个Messenger接口。这种方法,service定义了一个Handler处理不同类型的请求。Messenger能够和client分享一个IBinder,允许client使用Message发送请求。通常,client也可以定义一个Messenger,这样service可以将Message送回。
这是最简单的进程间通信,因为Messenger将所有的请求都入列到一个线程中,这意味着一次只能执行一个请求,所以你不必担心线程安全问题。
Using AIDL:
AIDL做了所有的工作使得可以将对象分解成操作系统可以理解的原语,然后在不同进程间执行IPC。Messenger方法底层就是使用了AIDL 的机制实现的。如果你想service能够同时处理多个请求,你可以直接使用AIDL。这种情况下,你必须实现多线程安全问题。
要使用AIDL,你必须创建一个.aidl文件来定义编程接口。你可以使用sdk工具来根据这个文件生成一个抽象类(继承该接口)处理IPC。
接下来你可以在service中继承该抽象类。
注意:大多数应用程序不该使用AIDL来创建一个bind service.因为这会造成多线程安全问题,如果你想实现,你可以参照android的AIDL文档。
继承Binder类:
注意:这仅仅只有client和service在同一个应用并且在同一个进程中才会有效。
1在service中创建一个IBinder对象:
1).包含一些public方法,这样client可以调用
2).返回当前service对象(包含一些public方法,client可以调用),
3).或者返回一个service的内部类包含一些public方法,这样client可以调用
2.在onBind方法中返回IBinder对象实例。
3.在client中,从onServiceConnected方法接收这个Binder。然后调用提供的方法调用服务。
注意:之所以client和service必须在同一个应用中是因为这样才可以使client转换返回的对象和调用它的apis。因为这种方法并不会在进程间通信,所以必须在同一进程运行。
例如:
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.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
LocalBInder提供了getService方法给client,并返回当前service对象。这样client就可以调用service的public方法。
下面的例子是activity调用service的public方法:
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();
// 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 (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
使用Messenger:
如果你希望你的service可以使用远程进程调用,你可以使用这种方法。它可以是你避免使用AIDL实现进程间通信。
如何使用:
1.service实现一个Handler接口,接收client的请求调用
2.这个Handler用来创建一个Messenger对象,并且包含了此handler的一个引用。
3.这个Messenger对象创建一个IBinder对象,并通过onBind方法返回给client。
4.client用这个IBinder对象实例化这个包含了service的handler的Messenger对象,client使用这个handler发送Message给service。
5.service在它的handleMessage方法中处理message。
这种方法,client不会调用service的方法,而是通过发送给service的message交给handler处理。
下面是一个例子:
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());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
client仅仅只需要根据service返回的IBinder对象在ServiceConnection的onServiceConnected方法中创建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;
}
}
}
如果你希望service应答,你需要自client中创建一个Messenger,当client接收到onServiceConnected方法时,通过send方法将messenger发送给service。
注意:仅仅activity,contentprovider,service可以绑定到一个服务,broadcastreceiver不能够绑定到一个服务
。
ServiceConnection:
onServiceConnected:系统调用这个方法传递由onBind方法返回的IBinder
onServiceDisconnected:系统会在和服务的连接意外丢失时调用此方法。例如:当service崩溃或者被杀死。client调用unBind方法时并不会调用此方法。
当client被销毁时,它会解除和service的绑定,但是你应该在和service完成交互时或者你的activity执行pause时解除绑定。这时,服务就可以在不用的时候结束。
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
第三个参数应该为BIND_AUTO_CREATE,这样在service还没有创建时可以创建service。
需要注意的地方:
1.你必须注意DeadObjectException,当连接破坏的时候会被调用。这是唯一的一个被远程方法抛出的异常。
2.objects是被跨进程引用计数。
3.你应该在client的匹配的生命周期进行onBind和unBind。
1)例如你只希望在activity可见时与服务通信,那么你可以在onStart中onBind,在onStop中unBind。
2)如果你想在activity停止时仍然可以收到结果,你可以在onCreate和onDestroy中执行。必须知道的是,这意味着你的activity在整个生命周期中都会使用service。
如果service运行在两外一个进程中,所以你增加了进程的杀死权重,系统很可能会杀死它。
注意:不要再activity的onResume和onPause方法中onBind和unBind。因为如果有多个activities绑定到一个服务。并且其中两个有一个过渡,那么你在过渡过程中首先可能会销毁服务,然后在下一个activity创建服务。
管理绑定服务的生命周期
如果你的服务接受绑定,当系统调用unBind方法时,如果你希望在下一次一个client绑定到service时被系统调用onRebind方法而不是onBind方法时,你可以在unBind方法中返回true。onRebind返回void,但是client仍然可以在onServiceConnected方法中接收到IBinder。下面是这种生命周期: