Service官方教程(8)Bound Service示例之2-跨进程使用Messenger
Compared to AIDL
When you need to perform IPC, using a Messenger
for your interface is simpler than implementing it with AIDL, because Messenger
queues all calls to the service, whereas, a pure AIDL interface sends simultaneous requests to the service, which must then handle multi-threading.
For most applications, the service doesn't need to perform multi-threading, so using a Messenger
allows the service to handle one call at a time. If it's important that your service be multi-threaded, then you should use AIDL to define your interface.
Using a Messenger
If you need your service to communicate with remote processes, then you can use a Messenger
to provide the interface for your service. This technique allows you to perform interprocess communication (IPC) without the need to use AIDL.
Here's a summary of how to use a Messenger
:
使用Messenger的步骤:
- The service implements a
Handler
that receives a callback for each call from a client. - The
Handler
is used to create aMessenger
object (which is a reference to theHandler
). - The
Messenger
creates anIBinder
that the service returns to clients fromonBind()
. - Clients use the
IBinder
to instantiate theMessenger
(that references the service'sHandler
), which the client uses to sendMessage
objects to the service. - The service receives each
Message
in itsHandler
—specifically, in thehandleMessage()
method.
In this way, there are no "methods" for the client to call on the service. Instead, the client delivers "messages" (Message
objects) that the service receives in its Handler
.
注意,这种方式下,服务端没有函数给客户端调用。它们只能发送消息。
Here's a simple example service that uses a Messenger
interface:
1 public class MessengerService extends Service { 2 /** Command to the service to display a message */ 3 static final int MSG_SAY_HELLO = 1; 4 5 /** 6 * Handler of incoming messages from clients. 7 */ 8 class IncomingHandler extends Handler { 9 @Override 10 public void handleMessage(Message msg) { 11 switch (msg.what) { 12 case MSG_SAY_HELLO: 13 Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show(); 14 break; 15 default: 16 super.handleMessage(msg); 17 } 18 } 19 } 20 21 /** 22 * Target we publish for clients to send messages to IncomingHandler. 23 */ 24 final Messenger mMessenger = new Messenger(new IncomingHandler()); 25 26 /** 27 * When binding to the service, we return an interface to our messenger 28 * for sending messages to the service. 29 */ 30 @Override 31 public IBinder onBind(Intent intent) { 32 Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show(); 33 return mMessenger.getBinder(); 34 } 35 }
Notice that the handleMessage()
method in the Handler
is where the service receives the incoming Message
and decides what to do, based on the what
member.
All that a client needs to do is create a Messenger
based on the IBinder
returned by the service and send a message using send()
. For example, here's a simple activity that binds to the service and delivers the MSG_SAY_HELLO
message to the service:
1 public class MessengerActivity extends Activity { 2 /** Messenger for communicating with the service. */ 3 Messenger mService = null; 4 5 /** Flag indicating whether we have called bind on the service. */ 6 boolean mBound; 7 8 /** 9 * Class for interacting with the main interface of the service. 10 */ 11 private ServiceConnection mConnection = new ServiceConnection() { 12 public void onServiceConnected(ComponentName className, IBinder service) { 13 // This is called when the connection with the service has been 14 // established, giving us the object we can use to 15 // interact with the service. We are communicating with the 16 // service using a Messenger, so here we get a client-side 17 // representation of that from the raw IBinder object. 18 mService = new Messenger(service); 19 mBound = true; 20 } 21 22 public void onServiceDisconnected(ComponentName className) { 23 // This is called when the connection with the service has been 24 // unexpectedly disconnected -- that is, its process crashed. 25 mService = null; 26 mBound = false; 27 } 28 }; 29 30 public void sayHello(View v) { 31 if (!mBound) return; 32 // Create and send a message to the service, using a supported 'what' value 33 Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0); 34 try { 35 mService.send(msg); 36 } catch (RemoteException e) { 37 e.printStackTrace(); 38 } 39 } 40 41 @Override 42 protected void onCreate(Bundle savedInstanceState) { 43 super.onCreate(savedInstanceState); 44 setContentView(R.layout.activity_messenger); 45 } 46 47 @Override 48 protected void onStart() { 49 super.onStart(); 50 // Bind to the service 51 bindService(new Intent(this, MessengerService.class), mConnection, 52 Context.BIND_AUTO_CREATE); 53 } 54 55 @Override 56 protected void onStop() { 57 super.onStop(); 58 // Unbind from the service 59 if (mBound) { 60 unbindService(mConnection); 61 mBound = false; 62 } 63 } 64 }
Notice that this example does not show how the service can respond to the client. If you want the service to respond, then you need to also create a Messenger
in the client. Then when the client receives the onServiceConnected()
callback, it sends a Message
to the service that includes the client's Messenger
in the replyTo
parameter of the send()
method.
You can see an example of how to provide two-way messaging in the MessengerService.java
(service) and MessengerServiceActivities.java
(client) samples.