码迷,mamicode.com
首页 > 移动开发 > 详细

Android Messenger 跨进程通信

时间:2014-09-01 17:59:43      阅读:383      评论:0      收藏:0      [点我收藏+]

标签:des   android   style   http   color   io   使用   java   strong   

 

如果你需要在不同进程间通信,你可以在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.                                     MSG_SET_VALUE, mValue, 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(this0,  

  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.                         mCallbackText.setText("Received from service: " + msg.arg1);  

  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.                 mCallbackText.setText("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.                 mCallbackText.setText("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.             mCallbackText.setText("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.                 mCallbackText.setText("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.             mCallbackText.setText("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" />  

Android Messenger 跨进程通信

标签:des   android   style   http   color   io   使用   java   strong   

原文地址:http://my.oschina.net/u/165172/blog/308806

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!