1.简介
Messenger,顾名思义即为信使,通过它可以在不同进程中传递Message对象,通过在Message中放入我们需要的入局,就可以轻松实现数据的跨进程传递了。Messenger是一种轻量级的IPC方案,其底层实现是AIDL。
Messenger的使用方法很简单,它对AIDL进程了封装,并且由于它一次只处理一个请求,因此在服务端我们不需要考虑同步的问题。
 
2.实现跨进程通信
1)服务端进程
首先我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象。然后在Service的onBind方法中返回这Messenger对象底层的Binder即可。
2)客户端进程
客户端进程中,首先需要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,并通过这个Messenger对象向服务端发送Message。此外,如果需要服务端响应客户端,我们就需要像服务端那样创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务器,服务器就可以通过这个replyTo参数回应客户端了。
 
     Messenger由于是在AIDL上进行了封装,其使用过程相对比较简单,下面的示例实现了客户端发送消息给服务端,服务端会根据客户端发送的消息予以回复并将回复的结果显示在客户端上。
3)下面直接贴上client和service的代码,最后附上运行结果。
Client:
package com.pignet.messengerdemo2; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; public class MainActivity extends AppCompatActivity {
private static TextView tvMsgFromService;
Button btnSend;
EditText etClient; private Messenger mService; private Messenger mGetReplyFromService =new Messenger(new MessengerHandler());
private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
tvMsgFromService.setText(msg.getData().getString("reply"));
break; }
super.handleMessage(msg);
}
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService=new Messenger(service);
} @Override
public void onServiceDisconnected(ComponentName name) { }
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSend= (Button) findViewById(R.id.btn_send);
etClient= (EditText) findViewById(R.id.et_client);
tvMsgFromService = (TextView) findViewById(R.id.tv_msg_from_service);
Intent intent= new Intent(MainActivity.this,MessengerService.class);
bindService(intent,mConnection, Context.BIND_AUTO_CREATE); btnSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String msgFromClient;
Message msg = Message.obtain(null,0);
Bundle data = new Bundle();
if((msgFromClient=String.valueOf(etClient.getText()))==null){
Toast.makeText(MainActivity.this,"The Message is null",Toast.LENGTH_SHORT).show();
}else{
data.putString("msg", msgFromClient);
msg.setData(data);
msg.replyTo= mGetReplyFromService;
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
} }
}); } @Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
}
Service:
package com.pignet.messengerdemo2;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log; /**
* Created by DB on 2017/7/2.
*/ public class MessengerService extends Service {
private static final String TAG="MessengerService"; private static class MessengerHandler extends Handler{
@Override
public void handleMessage(Message msg) { switch (msg.what){
case 0:
Log.i(TAG, "receive msg from client: "+msg.getData().getString("msg"));
Messenger mService = msg.replyTo;
Message replyMessage = Message.obtain(null,1);
Bundle bundle = new Bundle();
bundle.putString("reply","您的信息"+msg.getData().getString("msg")+"已收到,稍后会有回复");
replyMessage.setData(bundle);
try{
mService.send(replyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
}
super.handleMessage(msg);
}
} private final Messenger mMessenger = new Messenger(new MessengerHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
}
 
这里为了模拟不同应用间的跨进程通信,将Service类运行在了与Client不同的进程中,这样就可以实现和不同应用间通信一样的效果。
所以我们需要在manifests文件中加入:
<service android:name=".MessengerService"
android:process=":romote">
</service>

运行结果如下

 
 
3.Messenger源码浅析:
     进入到Messenger源码后,查看它的结构
Messenger类有两个构造函数,分别是可以用Handler和IBinder实现,这也是我们之前实现跨进程中通信中实例化Messenger类中已经用到的两种构造函数。
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}

因为之前提到过Messenger的底层实现是AIDL,所以这边我看这个IMessage和那个IBookManager有的类似,点开后发现确实如此

public interface IMessenger extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements
android.os.IMessenger {
private static final java.lang.String DESCRIPTOR = "android.os.IMessenger"; public Stub() {
this.attachInterface(this, DESCRIPTOR);
} public static android.os.IMessenger asInterface(...} public android.os.IBinder asBinder() {
return this;
} @Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags)
throws android.os.RemoteException {...} private static class Proxy implements android.os.IMessenger {...} public void send(android.os.Message msg)
throws android.os.RemoteException;
}

之前我们为BookManager类定义的方法是一个addBook和getBookList,而这边我们发现Messenger对AIDL的封装中加入的是一个send方法。

那这个方法是在哪里实现的呢。

private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}

它是在Handler类中的MessengerImpl方法中得到实现的,这也就可以解释我们发送的message可以在Handler的handleMessage中出现了。

最后我们再回到Messenger类中看看Messenger的另一个重要方法:

    public void send(Message message) throws RemoteException {
mTarget.send(message);
}

这里我们就可以串联起来了,Messenger类通过传入Handler或是IBinder来获得IMessenger的实例,然后调用send方法实际是在远程调用IMessenger的send方法。

这里我们就差不多把Messenger的机制理清了。

最后附上刚才实现的例子的一个简图:

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

  1. Android-Messenger跨进程通信

    http://blog.csdn.net/lmj623565791/article/details/47017485 一.概述 我们可以在客户端发送一个Message给服务端,在服务端的handler ...

  2. Android 进阶10:进程通信之 Messenger 使用与解析

    读完本文你将了解: Messenger 简介 Messenger 的使用 服务端 客户端 运行效果 使用小结 总结 代码地址 Thanks 前面我们介绍了 AIDL 的使用与原理,这篇文章来介绍下 A ...

  3. 【朝花夕拾】跨进程通信,你只知道AIDL,就OUT了

    一.前言 提起跨进程通信,大多数人首先会想到AIDL.我们知道,用AIDL来实现跨进程通信,需要在客户端和服务端都添加上aidl文件,并在服务端的Service中实现aidl对应的接口.如果还需要服务 ...

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

    在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...

  5. WinForm实现跨进程通信的方法

    public class WinMessageHelper { private struct COPYDATASTRUCT { public IntPtr dwData; public int cbD ...

  6. AIDL跨进程通信

    Android跨进程通信会用到AIDL,当然跨进程通信不一定要用AIDL,像广播也是可以的,当然这里用到AIDL相对比较安全一些: AIDL允许传递基本数据类型(Java 的原生类型如int/long ...

  7. 【Chromium中文文档】跨进程通信 (IPC)

    跨进程通信 (IPC) 转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//General_Architecture/I ...

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

    1.ContentProvider简单介绍 在Android中有些数据(如通讯录.音频.视频文件等)是要供非常多应用程序使用的.为了更好地对外提供数据.Android系统给我们提供了Content P ...

  9. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...

随机推荐

  1. 谷歌IAP:skusBundle array associated with key ITEM_ID_LIST cannot contain more than 20 items.

    这几天在接谷歌的支付,在拉谷歌商品列表的时候转菊花,长时间不返回(querySkuDetails),一开始以为因为IAP有key不对导致的,查了下发现没有问题. 再看logcat,发现了这行: Inp ...

  2. Jquery datatable 动态隐藏列(根据有无值)

    一场景: 前端利用datatable初始化的时候会向后端调用数据,需求是 要动态的使某一列根据传回来的一个标志位是否有值来决定显示与否 这是当前传回值有活动优惠幅度的情况下 这是没有活动优惠的情况下 ...

  3. SparkMLib分类算法之朴素贝叶斯分类

    SparkMLib分类算法之朴素贝叶斯分类 (一)朴素贝叶斯分类理解 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法.简单来说,朴素贝叶斯分类器假设样本每个特征与其他特征都不相关.举个例子, ...

  4. Ultimus BPM 零售和快消品行业应用解决方案

    Ultimus BPM 零售和快消品行业应用解决方案 行业应用需求 中国零售及快消品行业正在经历深刻变化.经济下滑,消费回落,行业危机继续发酵:人员工资.房租费用进一步上涨,成本高涨成为不能承受之重: ...

  5. Segmentation Faul

    转自:http://www.cnblogs.com/panfeng412/archive/2011/11/06/segmentation-fault-in-linux.html

  6. 可视化Git版本管理工具SourceTree的使用

    最近去了新公司,发现公司使用的团队版本管理工具是SourceTree,本人一直是SVN的热衷粉,很少使用git,所以从头学习git及可视化客户端SourceTree的使用,本贴只针对新手,大牛可以无视 ...

  7. 【面向对象设计原则】之接口隔离原则(ISP)

    接口隔离原则(Interface  Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口. 从接口隔离原则的定义可以看 ...

  8. angular实现的按钮提示

    用angularJS简单实现了一个小的按钮提示,html文件中需要引入jquery.js和angular.js css代码: <style type="text/css"&g ...

  9. 写给Android App开发人员看的Android底层知识(8)

    (十)PMS及App安装过程 PMS,全称PackageManagerService,是用来获取Apk包的信息的. 在前面分析四大组件与AMS通信的时候,我们介绍过,AMS总是会使用PMS加载包的信息 ...

  10. [机器学习实践] 针对Breast-Cancer数据集

    本篇博客中,我们将对一个UCI数据库中的数据集:Breast-Cancer数据集,应用已有的机器学习方法来实现一个分类器. 本文代码链接 数据集概况 数据集的地址为:link 在该页面中,可以进入Da ...