一.基础知识
bound service指的就是 一个继承service的类并且同一其它的应用去绑定它并且和它进行通信。
二.创建Bound Service
当创建一个提供绑定服务的service时,必须提供一个IBinder对象用来和客户端进行通信,有两种提供的方式:
1.Extending the Binder class
如果你的服务只是为你自己的app提供并且和客户端运行在同一个进程中,你应该这么做
(1)创建一个extend Binder的内部类,并且在onBinder()方法中返回该类的实例。
(2)客户端可以获得该Binder对象并且直接调用该类中的方法,甚至直接操作该类所在的Service(继承Binder类的类中实现一个方法,返回Service的实例)。
2.Using a Messenger(implements Parcelable)
如果你希望你的接口作用与不同的进程中,你可以为service创建一个interface通过Messenger的方式进行跨进程通信。在这种方式中,Service会定义一个Handler去回应不同类型的Message实例。
这是最简单的跨进程通信,因为Messager队列中所有的请求都是在仅有的唯一一个进程中的。所以你不需要为了线程安全来设计Service。(因为一次只处理一个请求,其他排队)
3.Using AIDL
AIDL的工作是分解objects变成简单的类型这样操作系统就可以理解并且安排它们横穿过进程,从而完成进程间的通信。之前的教程,通过Messenger的方式进程进程间的通信实际上也是基于AIDLde体系之上的。Messager创造了一个队列,所有客户端的请求都加入唯一的一个队列中,所以Service端一次只能接收一个请求。如果你想要你的Service端同步的处理多个请求,你可以直接使用AIDL。在这个情况下,你的Service要有处理多线程的能力并且可以保证线程安全。
三.几种方式如何使用
1.Extending the Binder class
这方法是应用场景:
client和service在同一个应用中并且在同一个进程中。
使用步骤:
(1)在你的service中创建一个Binder实例
(2)在onBinder()方法中返回Binder对象
(3)在client端通过onServiceConnected()回调方法获得Binder实例,并且利用该实例去获得Service的对象
eg:
service端
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); } }
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; } }; }
2.Using a Messenger
这方法是应用场景:
可以不用使用aidl来完成进程间的通信,可以使用Messenger来为Service提供接口。一次只能接收并处理一个请求
使用步骤:
(1)Service中实现一个Handler并实现一个回调函数(handleMessage)用来接收client的每次调用
(2)Handler被用来创造一个Messenger对象
(3)Messenger对象创建出一个IBinder对象,并在onBind中返回该对象
(4)client在onServiceConnection中接收到该IBinder对象,并用它来创建Messenger对象
(5)可以用该Messenger对象来调用sendMessage()方法,将message对象放入Messenger队列中(同一个进程),在Service端的handleMessage中进行接收,从而完成通信
eg:
service端:
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(); } }
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端,只是接收客户端的请求而已
如果你想service端做出回应,你需要在client也创建出Messenger对象,
四.一些注意点
1.应该总是抛出DeadObjectException异常,当连接意外中断时会抛出异常。
2.跨进程对象引用计数
3.binding和unbinding要同时使用
五.bound service时生命周期的管理
六.开发过程中遇到的坑