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. ZooKeeper实践:(1)配置管理

    一. 前言     配置是每个程序不可或缺的一部分,配置有多重方式:xml.ini.property.database等等,从最初的单机环境到现在的分布式环境. 1. 以文件的格式存储配置,修改任何都 ...

  2. 如何用php实现简单的文件上传功能?(带图解)

    如图所示:点击浏览出现选择文件的对话框,将所选文件上传到保存文件的文件.  关键点:文件上传的图解: 代码: <!DOCTYPE html> <html> <head&g ...

  3. MySQL unique 注意

    刚才修改表结构: alter table room add CONSTRAINT roomname_unique UNIQUE(roomname); 结果提示如下错误: ERROR : Specifi ...

  4. iframe 父子页面方法调用

    在写代码的时候经常会用到将一个网页嵌入到另一个网页中,w3c也规定了一个标签<iframe>,这个标签本身就支持跨域,而且所有的浏览器都支持 iframe具有以下属性: 1.framebo ...

  5. Spring Cloud 注册中心Eureka

    一.简介 最近在看Spring Cloud微服务,接下来的时间和大家一起分享我所看到的,公司现在用的是dubbo ,之后有时间也去了解了解dubbo的源码.与dubbo相比较,Spring Cloud ...

  6. 关于微信小程序遇到的wx.request({})问题

    域名请求错误问题 当我们在编写小程序,要发送请求时,wx.request({})时或许会遇到如下的问题: 一:这是因为微信小程序的开发中,域名只能是https方式请求,所以我们必须在小程序微信公众平台 ...

  7. 使用Git上传项目代码到github

    github是一个基于Git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开.这对于一般人来说公共仓库就已经足够了.   注册账户以及创建仓库 要想使用gi ...

  8. 001---Hibernate简介( 开源O/R映射框架)

    该系列教程是使用hibernate3,hibernate4和3有区别(集成spring,使用等),请注意 001---Hibernate简介(开源O/R映射框架) ORM(Object Relatio ...

  9. Lua 设置table为只读属性

    项目中部分只读表易被人误改写,故决定在非线上环境里对这些表附加只读属性,方便在出现误改写的时候抛出lua错误,最终版代码如下: --[[-------------------------------- ...

  10. Python一切皆对象

    Python从设计之初就是一门面向对象的语言,它有一个重要的概念,即一切皆对象. Java虽然也是面向对象编程的语言,但是血统没有Python纯正.比如Java的八种基本数据类型之一int,在持久化的 ...