Android进程间的通信方式可以通过以下两种方式完成:

 Android接口定义语言(AIDL)
使用Messenger绑定服务

本文我们将学习使用Messenger绑定服务的方式进行进程间的通信。

Android AIDL和Messenger区别

使用Messenger是执行进程间通信最简单的方法,因为Messenger会在单一线程中创建包含所有请求的队列,这样您就不必对服务进行线程安全设计。而纯粹的AIDL接口会同时向服务发送多个请求,服务随后必须应对多线程处理。AIDL通常应用在服务被设计到单独的应用中的场景(即服务端可客户端不属于同一个app的情况),而Messenger通常应用在同一app的不同进程的场景中。

Messenger基本思想

服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler(具体来讲:是Handler的子类)来创建Messenger,在onBind时返回Messenger的binder(调用Messenger的getBinder()方法,该方法返回一个IBinder对象,客户端将通过该对象作为参数创建一个Messenger对象用于与服务端进行通信)。

Messenger使用步骤

、服务端实现一个Handler,由其接收来自客户端的每个调用的回调
、使用第1步的Handler的实例作为target创建Messenger对象(即该Messenger持有了对Handler的引用)
、使用Messenger创建一个IBinder(通过调用Messenger的getBinder()方法),服务端的onBind()方法中将其返回到客户端
、客户端使用IBinder将Messenger(引用服务端的Handler实例)实例化,然后使用后者将Message对象发送给服务端
、服务端在其Handler中接收每个Message

这样,客户端并没有调用服务端的“方法”,而客户端传递的消息(Message对象)是服务端在其Handler中接收到的。

如果想让服务端对客户端发回响应,则还需要在客户端中创建一个持有客户端Handler实现类的Messenger,当客户端收到onServiceConnected()回调时,在向服务发送的Message时,send()方法的replyTo参数中需包含客户端的Messenger。这样,客户端就可在其Handler实现类中接收到来自服务端的响应消息。

简单示例

AndroidMainfest.xml

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="yf.exam.client.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MessengerService" android:process=":custom_process"/>
</application>

在上面的配置文件中,service的android:process属性用于在一个单独进程中启动service,看如下图片:

布局文件很简单,这里只有一个按钮,用于向服务端发送消息并显示服务端响应内容,这里不再给出。

客户端:MainActivity

 public class MainActivity extends Activity {
private static final int REPLY_MSG_ID = ;
private boolean mServiceConnected = false;
private Button btn = null;
//用于向Service端发送消息的Messenger
private Messenger mBoundServiceMessenger = null;
//用于接收Service发送消息的Messenger
private final Messenger mReceiveMessenger = new Messenger(new ReceiveMessHandler(this));
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mBoundServiceMessenger = null;
mServiceConnected = false;
} @Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBoundServiceMessenger = new Messenger(service);
mServiceConnected = true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button);
bindService(new Intent(this, MessengerService.class), conn, Context.BIND_AUTO_CREATE);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mServiceConnected){
//获取消息对象
Message msg = Message.obtain(null, , , );
try{
//replyTo参数包含客户端Messenger
msg.replyTo = mReceiveMessenger;
//向Service端发送消息
mBoundServiceMessenger.send(msg);
}catch(RemoteException re){
re.printStackTrace();
}
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mServiceConnected){
unbindService(conn);
mServiceConnected = false;
}
}
/**
* 客户端实现一个Handler用于接收服务端返回的响应
* @author Administrator
*
*/
static class ReceiveMessHandler extends Handler{
//持有当前Activity的弱引用,避免内存泄露
private final WeakReference<MainActivity> mActivity;
public ReceiveMessHandler(MainActivity activity){
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case REPLY_MSG_ID:
Toast.makeText(mActivity.get(), msg.getData().getString("msg"), Toast.LENGTH_SHORT).show();
break;
}
}
}
}

服务端:MessengerService.java

 public class MessengerService extends Service {
private static final int REPLY_MSG_ID = ;
private static final int MSG_ID = ;
static class BoundServiceHandler extends Handler{
private final WeakReference<MessengerService> mService;
public BoundServiceHandler(MessengerService service){
mService = new WeakReference<MessengerService>(service);
}
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case MSG_ID:
Messenger replyMessenger = msg.replyTo;
Message replyMsg = Message.obtain(null, REPLY_MSG_ID);
//向客户端响应的消息内容
Bundle b = new Bundle();
b.putString("msg", "this is the message reply from service");
replyMsg.setData(b);
try{
replyMessenger.send(replyMsg);
}catch(RemoteException re){
re.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
private final Messenger mMessenger = new Messenger(new BoundServiceHandler(this));
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}

此外,上述例子中所有的Handler的实现类都被声明为static并使用Service或Activity的WeakReference。如果不这样做,编译器会给出警告信息“This handler class should be static or leaks might occur”。通过使用弱引用的方式,就允许Service或Activity进行垃圾收集了。

Android进程间的通信之Messenger的更多相关文章

  1. Android进程间的通信之AIDL

    Android服务被设计用来执行很多操作,比如说,可以执行运行时间长的耗时操作,比较耗时的网络操作,甚至是在一个单独进程中的永不会结束的操作.实现这些操作之一是通过Android接口定义语言(AIDL ...

  2. 从AIDL开始谈Android进程间Binder通信机制

    转自: http://tech.cnnetsec.com/585.html 本文首先概述了Android的进程间通信的Binder机制,然后结合一个AIDL的例子,对Binder机制进行了解析. 概述 ...

  3. Android进程间的通信

    1.概述:由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于 ...

  4. Android 进程间的通信

    localsocket:   https://blog.csdn.net/azhengye/article/details/73863404 https://www.cnblogs.com/basta ...

  5. Android进阶笔记04:Android进程间通讯(IPC)之Messenger

    一. Android进程间通讯之Messenger 的引入 (1)引言:      平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯.它是基于消 ...

  6. android 进程间通信 messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯? android 消息机制 进程间 android 进程间 可以用 handler么 messenger 与 handler 机制 messenger 机制 是不是 就是 handler 机制 或 , 是不是就是 消息机制 android messenge

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha messenger 是什么 binder 跟 aidl 区别 intent 进程间 通讯 ...

  7. Android 使用AIDL实现进程间的通信

    在Android中,如果我们需要在不同进程间实现通信,就需要用到AIDL技术去完成. AIDL(android Interface Definition Language)是一种接口定义语言,编译器通 ...

  8. Android进程间通讯

    最近研究了一下Android进程间通讯,原来只是会用,但是只是会用是不行滴,就来研究一下. 刚开始看的时候,我的头是这么大,看了一夜的时候,头就变成这样了,,吓得宝宝赶紧上床休息了,. 先喝喝茶讲个故 ...

  9. Android 进程间通讯方式

    Android 进程间通讯方式 1.通过单向数据管道传递数据 管道(使用PipedWriter/ 创建PipedReader)是java.io包的一部分.也就是说,它们是一般的Java功能,而不是An ...

随机推荐

  1. 完全卸载Oracle11G

    要特别注意删除注册表的这块,如果删错了会导致系统出现问题,而且oracle的安装卸载真的很烦,一旦装错了,卸载不干净就会导致种种的问题无法再次安装,个人建议用360卸载,360卸载完成后会自动检测到无 ...

  2. java后台调用url无协议

    url格式不正确,可能有"www.baidu.com"    "这个不能有 // 下载pdf public void downpdf(String URL, String ...

  3. html5 定位 获得当前位置的经纬度

    if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition, showError, { // ...

  4. JavaBean,POJO,VO,DTO的区别和联系

    JavaBeans A JavaBean is a class that follows the JavaBeans conventions as defined by Sun. Wikipedia ...

  5. sea.js 入门

    上个月学了 require.js 现在顺便来学学 sea.js. 对比下这两种的区别,看自己喜欢哪个,就在接下来的项目中去使用它吧. seajs中的所有 JavaScript 模块都遵循 CMD 模块 ...

  6. mxnet安装

    本来不想写这些玩意,但是老是纠缠安装环境,索性自己记一下. 我是在别人的基础上增加的,所以比较全. 裸机开始安装: 1.基本依赖的安装 sudo apt-get update sudo apt-get ...

  7. Centos安装jdk

    运行Java应用的时候,提示无法找到JAVA_HOME,查询java -version [jifeng@localhost bin]$ java -version java version " ...

  8. Using Redis to store php session

    Using Redis to store php session 默认情况下,php将会将session信息存储在文件系统上,在单机情况下没有问题,但是当系统负载增大,或者在对系统可用性要求很高的场景 ...

  9. 微信公众平台开发 微信JSSDK开发

    根据微信开发文档步骤如下: 1.先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”. JS接口安全域名设置 mi.com(前面不用带www/http,域名必须备案过) 2.引 ...

  10. strcpy 和 strcat

    strcpy 原型:char *strcpy( char *dest, char *src )  头文件:#include <string.h> 功能:将src地址开始且含有NULL结束符 ...