Android Messenger 跨进程通信

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

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

register:

[html]

  1. <service Android:name=".app.MessengerService"
  2. android:process=":remote" />
时间: 2024-10-05 19:44:49

Android Messenger 跨进程通信的相关文章

Android Binder跨进程通信原理分析

出发前预备子弹 我们知道进程之间,虚拟地址不同,是不能直接通信的,这是一种保护机制.打开任务管理器,查看一下N多的进程,试想一下如果这些进程直接通信会带来什么后果? 而用户空间可以通过System calls(系统回调)与内核空间通信的,如果在内核空间中有一个模块,能够完成数据的转发,那么是不是两个进程就可以通信了呢?如下图: 上面提到一些用户空间.内核空间的概念,用户空间也能大概猜到是什么东西,而内核空间,就知道它是很底层的东西好了.而模块呢,可以简单的理解为实现一个功能的程序或一个硬件电路等

messenger跨进程通信出现ClassNotFoundException...

利用messenger实现remote进程的service和主进程通信的时候报错com.xxx.xxx.xxx.bean.xxxbean on path: DexPathList[[directory .],nativeLibraryDirectories=[/vendor/lib, /data/cust/lib, /system/lib]] 看log发现错误处是在client解析从service发过来的message中的bundle对象, 网上搜了有人说是因为类加载器的问题,然后自己在   d

Android基础——Messenger在跨进程通信中的使用

Messenger在跨进程通信中的使用 事先说明: 本人也是个初学者,所以本文是从初学者的角度入手,如果有不妥的地方请留言教导我,谢谢. 本篇文章主要针对讲解Messenger的使用和Messenger在应用层上的原理解析和Messenger在服务端的回复. 什么是Messenger? Messenger可以翻译为信使,Messenger是一种轻量级的IPC方案,通过它可以在不同进程中传递Message对象,在Message中放入我们需要传递的数据,就可以实现数据的进程间传递了. 步骤一:Mes

跨进程通信之Messenger

1.简介 Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了.Messenger是一种轻量级的IPC方案,其底层实现是AIDL. Messenger的使用方法很简单,它对AIDL进程了封装,并且由于它一次只处理一个请求,因此在服务端我们不需要考虑同步的问题. 2.实现跨进程通信 1)服务端进程 首先我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通

android 远程Service以及AIDL的跨进程通信

在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问题了. 转换成远程Service非常简单,只需要在注册Service的时候将他的android:process的属性制定成 :remote就可以了. 重新运行项目,你会发现,不会出现ANR了. 为什么将MyService转换成远程Service后就不会导致程序ANR了呢?这是由于,使用了远程Serv

Android中的跨进程通信方法实例及特点分析(二):ContentProvider

1.ContentProvider简单介绍 在Android中有些数据(如通讯录.音频.视频文件等)是要供非常多应用程序使用的.为了更好地对外提供数据,Android系统给我们提供了Content Provider使用,通过它能够訪问上面所说的数据.比如非常多音乐播放器中的扫描功能事实上就用到了Content Provider功能(当然,也有的播放器是自己去实现更底层的功能). 这种优点是统一管理,比方添加了某个音频文件,底层就会将这种变化通知Content Provider.从而当应用程序訪问

Android基础笔记(十二)- 使用AIDL来进行跨进程通信

绑定服务调用服务里方法的过程 音乐盒小案例 利用服务注册特殊广播接收者 使用AIDL来进行跨进程通信 绑定服务调用服务里方法的过程 整个Activty绑定Service并调用其中方法的过程可以体现为下面的一张图,其中的核心是通过借助中间人IBinder来达到调用Service中方法的目的.. 接下来在明确一下调用过程的代码步骤: ①首先服务里有一个方法需要被调用 ②定义一个中间人对象(继承Bidner类的内部类MyBinder) ③在onBind方法中把我们自己定义的中间人返回MyBinder

Android中的跨进程通信方法实例及特点分析(一):AIDL Service

转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481 最近有一个需求就是往程序中加入大数据的采集点,但是因为我们的Android程序包含两个进程,所以涉及到跨进程通信的问题.现将Android中的跨进程通信方式总结如下. Android中有4种跨进程通信方式,分别是利用AIDL Service.ContentProvider.Broadcast.Activity实现. 1.利用AIDL Service实现跨进程通信 这是

Android随笔之——跨进程通信(一) Activity篇

在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一个应用调用了另一个应用,并传递了一定的数据.在Android中有Activity.Content Provider.BroadcastReceiver.Service四大组件,巧的是Android进程间通信也离不开这四大组件(也有说是AIDL机制,但是现在还分不清Service和AIDL的区别(/