如果你需要在不同进程间通信,你可以在Service中使用Messenger来实现进程中通信。

如果使用这种方式,Service中需要定义一个Handler对象(负责对客户端发送过来的Message进行响应)。

Messenger可以共享给client一个IBinder对象,client通过这个IBinder对象向Service发送Message,而前面提到的Handler对象是这一切的基础。

注:使用这种方式进行通信是不支持多线程的。

那就让我们来看看使用这种方式进行通信吧!

注:Service在声明时必须对外开放,即android:exported="true",且本文是通过Intent启动的Service,所以在声明时该Service可以接收特定的Action。

1、在Service中创建一个Handler对象,来处理从client发过来的Message

2、根据创建的Handler对象创建一个Messenger对象

3、使用Messenger的getBinder方法得到一个IBinder对象,并在Service的onBind方法中将其反出去

4、client在onServiceConnected中根据IBinder参数创建一个Messenger对象(可参考Messenger的构造函数)

5、client可以使用上一步得到的Messenger对象来给Service发送Message了

经过上面的五部我们就能让client与Service进行通信。client使用Messenger对象给Service发送Message后,Service中的Handler将会对消息作出响应。

上面实现的仅仅是单向通信,即client给Service发送消息,如果我需要Service给client发送消息又该怎样做呢?

其实,这也是很容易实现的,下面就让我们接着上面的步骤来实现双向通信吧~

6、在client中创建一个Handler对象,用于处理Service发过来的消息

7、根据client中的Handler对象创建一个client自己的Messenger对象

8、我们在第5步的时候获得了Service的Messenger对象,并通过它来给Service发送消息。这时候,我们将client的Messenger对象赋给待发送的Message对象的replyTo字段

9、在Service的Handler处理Message时将client的Messenger解析出来,并使用client的Messenger对象给client发送消息

这样我们就实现了client和Service的双向通信。client和Service都有自己的Handler和Messenger对象,使得对方可以给自己发送消息,值得注意的是client的Messenger是通过Message的replyTo传递给Service的。

Messenger:信使

官方文档解释:它引用了一个Handler对象,以便others能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message的通信(即两个进程间可以通过Message进行通信),在服务端使用Handler创建一个Messenger,客户端持有这个Messenger就可以与服务端通信了。

以前我们使用Handler+Message的方式进行通信,都是在同一个进程中,从线程持有一个主线程的Handler对象,并向主线程发送消息。

而Android既然可以使用bindler机制进行跨进行通信,所以我们当然可以将Handler与bindler结合起来进行跨进程发送消息。

查看API就可以发现,Messenger就是这种方式的实现。

一般使用方法如下:

1。远程通过

mMessenger = new Messenger(mHandler)  

 创建一个信使对象

2。客户端使用bindlerService请求连接远程

3。远程onBind方法返回一个bindler

return mMessenger.getBinder();  

 4.客户端使用远程返回的bindler得到一个信使(即得到远程信使)

public void onServiceConnected(ComponentName name, IBinder service) {    
              rMessenger = new Messenger(service);      
             ...... 
 }

 这里虽然是new了一个Messenger,但我们查看它的实现

 public Messenger(IBinder target) {      mTarget = IMessenger.Stub.asInterface(target);  }  

 发现它的mTarget是通过Aidl得到的,实际上就是远程创建的那个。

5。客户端可以使用这个远程信使对象向远程发送消息:rMessenger.send(msg);

这样远程服务端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。(该Handler对象就是第一步服务端创建Messenger时使用的参数mHandler).

经过这5个步骤貌似只有客户端向服务端发送消息,这样的消息传递是单向的,那么如何实现双向传递呢?

首先需要在第5步稍加修改,在send(msg)前通过msm.replyTo = mMessenger将自己的信使设置到消息中,这样服务端接收到消息时同时也得到了客户端的信使对象了,然后服务端可以通过/得到客户端的信使对象,并向它发送消息  cMessenger = msg.replyTo;  cMessenger.send(message);  

 即完成了从服务端向客户端发送消息的功能,这样客服端可以在自己的Handler对象的handlerMessage方法中接收服务端发送来的message进行处理。

双向通信宣告完成。

以下代码来自ApiDemo

Service code:

[java]

1. public class MessengerService extends Service {  
2. /** For showing and hiding our notification. */
3.     NotificationManager mNM;  
4. /** Keeps track of all current registered clients. */
5.     ArrayList<Messenger> mClients = new ArrayList<Messenger>();  
6. /** Holds last value set by a client. */
7.     int mValue = 0;  
8.       
9. /**
10.      * Command to the service to register a client, receiving callbacks
11.      * from the service.  The Message's replyTo field must be a Messenger of
12.      * the client where callbacks should be sent.
13.      */
14.     static final int MSG_REGISTER_CLIENT = 1;  
15.       
16. /**
17.      * Command to the service to unregister a client, ot stop receiving callbacks
18.      * from the service.  The Message's replyTo field must be a Messenger of
19.      * the client as previously given with MSG_REGISTER_CLIENT.
20.      */
21.     static final int MSG_UNREGISTER_CLIENT = 2;  
22.       
23. /**
24.      * Command to service to set a new value.  This can be sent to the
25.      * service to supply a new value, and will be sent by the service to
26.      * any registered clients with the new value.
27.      */
28.     static final int MSG_SET_VALUE = 3;  
29.       
30. /**
31.      * Handler of incoming messages from clients.
32.      */
33.     class IncomingHandler extends Handler {  
34. @Override
35.         public void handleMessage(Message msg) {  
36.             switch (msg.what) {  
37.                 case MSG_REGISTER_CLIENT:  
38.                     mClients.add(msg.replyTo);  
39.                     break;  
40.                 case MSG_UNREGISTER_CLIENT:  
41.                     mClients.remove(msg.replyTo);  
42.                     break;  
43.                 case MSG_SET_VALUE:  
44.                     mValue = msg.arg1;  
45.                     for (int i = mClients.size() - 1; i >= 0; i --) {  
46.                         try {  
47.                             mClients.get(i).send(Message.obtain(null,  
48. 0));  
49.                         } catch (RemoteException e) {  
50. // The client is dead.  Remove it from the list; 
51. // we are going through the list from back to front 
52. // so this is safe to do inside the loop. 
53.                             mClients.remove(i);  
54.                         }  
55.                     }  
56.                     break;  
57.                 default:  
58.                     super.handleMessage(msg);  
59.             }  
60.         }  
61.     }  
62.       
63. /**
64.      * Target we publish for clients to send messages to IncomingHandler.
65.      */
66.     final Messenger mMessenger = new Messenger(new IncomingHandler());  
67.       
68. @Override
69.     public void onCreate() {  
70.         mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);  
71.   
72. // Display a notification about us starting. 
73.         showNotification();  
74.     }  
75.   
76. @Override
77.     public void onDestroy() {  
78. // Cancel the persistent notification. 
79.         mNM.cancel(R.string.remote_service_started);  
80.   
81. // Tell the user we stopped. 
82.         Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();  
83.     }  
84.       
85. /**
86.      * When binding to the service, we return an interface to our messenger
87.      * for sending messages to the service.
88.      */
89. @Override
90.     public IBinder onBind(Intent intent) {  
91.         return mMessenger.getBinder();  
92.     }  
93.   
94. /**
95.      * Show a notification while this service is running.
96.      */
97.     private void showNotification() {  
98. // In this sample, we'll use the same text for the ticker and the expanded notification 
99.         CharSequence text = getText(R.string.remote_service_started);  
100.   
101. // Set the icon, scrolling text and timestamp 
102.         Notification notification = new Notification(R.drawable.stat_sample, text,  
103.                 System.currentTimeMillis());  
104.   
105. // The PendingIntent to launch our activity if the user selects this notification 
106.         PendingIntent contentIntent = PendingIntent.getActivity(this, 0,  
107.                 new Intent(this, Controller.class), 0);  
108.   
109. // Set the info for the views that show in the notification panel. 
110.         notification.setLatestEventInfo(this, getText(R.string.remote_service_label),  
111.                        text, contentIntent);  
112.   
113. // Send the notification. 
114. // We use a string id because it is a unique number.  We use it later to cancel. 
115.         mNM.notify(R.string.remote_service_started, notification);  
116.     }  
117. }

Client code:

[java]

1. public class MessengerServiceActivities {  
2. /**
3.      * Example of binding and unbinding to the remote service.
4.      * This demonstrates the implementation of a service which the client will
5.      * bind to, interacting with it through an aidl interface.</p>
6.      * 
7.      * <p>Note that this is implemented as an inner class only keep the sample
8.      * all together; typically this code would appear in some separate class.
9.      */
10.     public static class Binding extends Activity {  
11.   
12. /** Messenger for communicating with service. */
13.         Messenger mService = null;  
14. /** Flag indicating whether we have called bind on the service. */
15.         boolean mIsBound;  
16. /** Some text view we are using to show state information. */
17.         TextView mCallbackText;  
18.           
19. /**
20.          * Handler of incoming messages from service.
21.          */
22.         class IncomingHandler extends Handler {  
23. @Override
24.             public void handleMessage(Message msg) {  
25.                 switch (msg.what) {  
26.                     case MessengerService.MSG_SET_VALUE:  
27. "Received from service: "
28.                         break;  
29.                     default:  
30.                         super.handleMessage(msg);  
31.                 }  
32.             }  
33.         }  
34.           
35. /**
36.          * Target we publish for clients to send messages to IncomingHandler.
37.          */
38.         final Messenger mMessenger = new Messenger(new IncomingHandler());  
39.           
40. /**
41.          * Class for interacting with the main interface of the service.
42.          */
43.         private ServiceConnection mConnection = new ServiceConnection() {  
44.             public void onServiceConnected(ComponentName className,  
45.                     IBinder service) {  
46. // This is called when the connection with the service has been 
47. // established, giving us the service object we can use to 
48. // interact with the service.  We are communicating with our 
49. // service through an IDL interface, so get a client-side 
50. // representation of that from the raw service object. 
51.                 mService = new Messenger(service);  
52. "Attached.");  
53.   
54. // We want to monitor the service for as long as we are 
55. // connected to it. 
56.                 try {  
57.                     Message msg = Message.obtain(null,  
58.                             MessengerService.MSG_REGISTER_CLIENT);  
59.                     msg.replyTo = mMessenger;  
60.                     mService.send(msg);  
61.                       
62. // Give it some value as an example. 
63.   
64.                     msg = Message.obtain(null,  
65.                             MessengerService.MSG_SET_VALUE, this.hashCode(), 0);  
66.   
67.                     mService.send(msg);  
68.                 } catch (RemoteException e) {  
69. // In this case the service has crashed before we could even 
70. // do anything with it; we can count on soon being 
71. // disconnected (and then reconnected if it can be restarted) 
72. // so there is no need to do anything here. 
73.                 }  
74.                   
75. // As part of the sample, tell the user what happened. 
76.                 Toast.makeText(Binding.this, R.string.remote_service_connected,  
77.                         Toast.LENGTH_SHORT).show();  
78.             }  
79.   
80.             public void onServiceDisconnected(ComponentName className) {  
81. // This is called when the connection with the service has been 
82. // unexpectedly disconnected -- that is, its process crashed. 
83.                 mService = null;  
84. "Disconnected.");  
85.   
86. // As part of the sample, tell the user what happened. 
87.                 Toast.makeText(Binding.this, R.string.remote_service_disconnected,  
88.                         Toast.LENGTH_SHORT).show();  
89.             }  
90.         };  
91.           
92.         void doBindService() {  
93. // Establish a connection with the service.  We use an explicit 
94. // class name because there is no reason to be able to let other 
95. // applications replace our component. 
96.             bindService(new Intent(Binding.this,   
97.                     MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);  
98.             mIsBound = true;  
99. "Binding.");  
100.         }  
101.           
102.         void doUnbindService() {  
103.             if (mIsBound) {  
104. // If we have received the service, and hence registered with 
105. // it, then now is the time to unregister. 
106.                 if (mService != null) {  
107.                     try {  
108.                         Message msg = Message.obtain(null,  
109.                                 MessengerService.MSG_UNREGISTER_CLIENT);  
110.                         msg.replyTo = mMessenger;  
111.                         mService.send(msg);  
112.                     } catch (RemoteException e) {  
113. // There is nothing special we need to do if the service 
114. // has crashed. 
115.                     }  
116.                 }  
117.                   
118. // Detach our existing connection. 
119.                 unbindService(mConnection);  
120.                 mIsBound = false;  
121. "Unbinding.");  
122.             }  
123.         }  
124.   
125.           
126. /**
127.          * Standard initialization of this activity.  Set up the UI, then wait
128.          * for the user to poke it before doing anything.
129.          */
130. @Override
131.         protected void onCreate(Bundle savedInstanceState) {  
132.             super.onCreate(savedInstanceState);  
133.   
134.             setContentView(R.layout.messenger_service_binding);  
135.   
136. // Watch for button clicks. 
137.             Button button = (Button)findViewById(R.id.bind);  
138.             button.setOnClickListener(mBindListener);  
139.             button = (Button)findViewById(R.id.unbind);  
140.             button.setOnClickListener(mUnbindListener);  
141.               
142.             mCallbackText = (TextView)findViewById(R.id.callback);  
143. "Not attached.");  
144.         }  
145.   
146.         private OnClickListener mBindListener = new OnClickListener() {  
147.             public void onClick(View v) {  
148.                 doBindService();  
149.             }  
150.         };  
151.   
152.         private OnClickListener mUnbindListener = new OnClickListener() {  
153.             public void onClick(View v) {  
154.                 doUnbindService();  
155.             }  
156.         };  
157.     }  
158. }

register:

[html]

1. <service Android:name=".app.MessengerService"
2. android:process=":remote" />