0.  前言

不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPC(Inter-Process Communication)即进程间通信。首先线程和进程是很不同的概念,线程是CPU调用的最小单元,进程一般在PC和移动设备上指一个程序或者一个应用,一个进程可以包含多个线程。

IPC方式有很多,在Android中常用的IPC方式包括Bundle、文件、Messenger、AIDL、ContentProvider和Socket等方式。

本篇主要讲解使用Messenger的方式。本文原创,转载请注明出处为SEU_Calvin的博客

1.  Messenger

Messenger是系统为我们封装好的一套IPC方案,它的底层是基于AIDL与Handler。使用Messenger可以在不同进程中传递Message对象,并在Message中放入我们需要传递的数据,就可以实现数据的进程间通信了。

Messenger的构造方法如下所示:

public Messenger(Handler target) {
mTarget = target.getIMessenger();
} public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}

既然是进程间通信吗,那么直接看代码好了,先看服务器端所在进程的代码:

public class MessengerService extends Service {
private static final String Messenger_TAG = "Messenger";
private static class ServerMessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
// 接收到客户端的信息
Log.i(Messenger_TAG, msg.getData().getString("client-data") + " " + Thread.currentThread().toString());
// 返回信息给客户端
Messenger replyMessenger = msg.replyTo;
Message message = Message.obtain();
message.what = 1;
Bundle data = new Bundle();
data.putString("server-data", "hello client, I have received your message! ");
message.setData(data);
try {
replyMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
} // 服务端Messenger
private Messenger serverMessenger = new Messenger(new ServerMessengerHandler()); @Override
public IBinder onBind(Intent intent) {
return serverMessenger.getBinder();
}
}

服务器端创建一个Service来处理客户端的连接请求,同时创建一个Handler并以此为参数实例一个Messenger来接收客户端Messenger发来的message,最后在onBind方法返回这个Messenger的Binder。在handleMessage()中不仅展示了客户端传来的信息,还使用Messenger replyMessenger =msg.replyTo获取客户端Messenger对象,装载数据后通过replyMessenger.send(message)返回message信息给客户端。完成了回复的功能。最后看一个客户端的代码:

public class MainActivity extends AppCompatActivity {
private static final String Messenger_TAG = "Messenger";
private Messenger clientMessenger;
private Button button;
// 接收服务端返回信息的Messenger
private Messenger replyMessenger = new Messenger(new ClientMessengerHandler());
private static class ClientMessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
// 接收到服务端返回的信息
Log.i(Messenger_TAG, msg.getData().getString("server-data") + " " + Thread.currentThread().toString());
break;
default:
super.handleMessage(msg);
}
}
} private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
clientMessenger = new Messenger(service);
} @Override
public void onServiceDisconnected(ComponentName name) {
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.messenger); // bind服务端Service
Intent intent = new Intent(this, MessengerService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE); button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 发送消息到服务端
Message message = Message.obtain();
message.what = 0;
Bundle data = new Bundle();
data.putString("client-data", "hello server");
message.setData(data); // 指定接收服务端返回信息的Messenger
message.replyTo = replyMessenger; try {
clientMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}); } @Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}

首先在onCreate()中使用bindService()绑定服务,绑定成功后回调onServiceConnected()并在其中获得服务器返回的Binder对象,并通过这个Binder对象创建出Messenger对象clientMessenger。这里需要注意的是,与服务的连接意外中断时(例如当服务崩溃或被终止时)会回调onServiceDisconnected()方法。而当客户端主动取消绑定时,则不会调用该方法。

点击按钮后clientMessenger.send(message)向服务器端发送消息,注意这里message消息通过replyTo生成了replyMessenger实例,即接收服务端返回信息的Messenger,并在其构造参数中自定义了接收并处理服务端返回信息的Handler。

点击按钮后结果如下,在两个进程中分别打印出信息:

这样整个客户端和服务端的跨进程通信过程就使用Messenger完成了。参考源码点击下载

Messenger 会在单一线程中创建包含所有客户端请求的队列,如果你想让服务同时处理多个请求,则可直接使用 AIDL。在此情况下,你的服务必须具备多线程处理能力,并采用线程安全式设计。

因此AIDL和经过封装的Messenger相比,最大的不同就是AIDL具备多线程处理能力,下一篇将介绍使用AIDL进行进程间通信的介绍。

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

  1. Android开发——进程间通信之AIDL(二)

    0.  前言 不论是Android还是其它操作系统.都会有自己的IPC机制.所谓IPC(Inter-Process Communication)即进程间通信.首先线程和进程是非常不同的概念,线程是CP ...

  2. Android开发——进程间通信之Bundle和文件

    0.  前言 不论是Android还是其他操作系统,都会有自己的IPC机制,所谓IPC(Inter-Process Communication)即进程间通信.首先线程和进程是很不同的概念,线程是CPU ...

  3. android开发之使用Messenger实现service与activity交互

    service与activity交互的方式有多种,这里说说使用Messenger来实现两者之间的交互. Service程序 public class MessengerService extends ...

  4. Android开发艺术探索读书笔记——进程间通信

    1. 多进程使用场景 1) 应用某些模块由于特殊需求须要执行在单独进程中. 如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会由于应用程序进程crash而受影响. 2) 为加大一个应用可 ...

  5. Android开发高级进阶——多进程间通信

    一. 什么是多进程? 多进程就是多个进程的意思,那么什么是进程呢? 当一个应用在开始运行时,系统会为它创建一个进程,一个应用默认只有一个进程,这个进程(主进程)的名称就是应用的包名. 进程的特点: 进 ...

  6. Android开发面试经——5.常见面试官提问Android题①

    版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客: http://blog.csdn.net/f ...

  7. Android开发全套视频教程在线观看网盘下载

    千锋金牌讲师老罗老师简介: 国内第一批Android教学讲师,10多年软件开发经验,6年多教学经验,曾担任广东电信北京分公司移动事业部项目经理,主持过微软中国平台考试系统.山西省旅游局智能化平台等大型 ...

  8. 《Android开发艺术探索》读书笔记 (2) 第2章 IPC机制

    2.1 Android IPC简介 (1)任何一个操作系统都需要有相应的IPC机制,Linux上可以通过命名通道.共享内存.信号量等来进行进程间通信.Android系统不仅可以使用了Binder机制来 ...

  9. 《android开发艺术探索》读书笔记(二)--IPC机制

    接上篇<android开发艺术探索>读书笔记(一) No1: 在android中使用多进程只有一种方法,那就是给四大组件在AndroidMenifest中指定android:process ...

随机推荐

  1. chrome中workspace配置达到同步修改本地文件的作用

    在前端开发中,我们经常需要在浏览器中进行调试,特别是一些样式的修改,如果你还是先在浏览器elements中调试好在复制到本地文件,那就真的out了. chrome浏览器的workspace功能完全可以 ...

  2. ELF文件结构描述

    ELF目标文件格式最前部ELF文件头(ELF Header),它包含了描述了整个文件的基本属性,比如ELF文件版本.目标机器型号.程序入口地址等.其中ELF文件与段有关的重要结构就是段表(Sectio ...

  3. 将目录结构输出为json格式(zTree)

    # -*- coding: UTF-8 -*- import json,os path = 'E:\\BACKUP' #返回空目录 def path_to_dict(path): d = {'name ...

  4. Redis雪崩、穿透、热点key等优化

    一.缓存 Redis做缓存是最常见的应用场景.客户端请求在缓存层命中就直接返回,如果miss就去读取存储层,存储层读取到就写入缓存层,然后再返回到客户端. 优点: 加速读写 降低后端负载 缺点: 数据 ...

  5. 【C语言】 使用Beep() 函数 演奏歌曲

    #include <windows.h> int main(){ ){ Beep(, ); Beep(, ); Beep(, ); Beep(, ); Beep(, ); Beep(, ) ...

  6. 实现一个协程版mysql连接池

    实现一个协程版的mysql连接池,该连接池支持自动创建最小连接数,自动检测mysql健康:基于swoole的chanel. 最近事情忙,心态也有点不积极.技术倒是没有落下,只是越来越不想写博客了.想到 ...

  7. TiDB数据库 mydumper命令导出数据报错:(mydumper:1908): CRITICAL **: Couldn't acquire global lock, snapshots will not be consistent: Access denied for user 'super'@'%' (using password: YES)

    今天想使用Tidb官方提供的mydumper来备份AWS上的RDS集群中mysql数据库的某个表,发现报错了 [tidb@:xxx /usr/local/tidb-tools]$ -t -F -B x ...

  8. Azure IoT 预配置解决方案

    Azure IoT 预配置解决方案 Sangyu Li © 2018  一.什么是Azure IoT 预配置解决方案? 如图,这就是Azure IoT Suite中 Provision solutio ...

  9. SDN负载均衡

    我负责的工作: (1).前期工作思路设计及方案选定.讲解 (2).后期代码修正 (3).视频制作 负载均衡程序 程序流程图 代码 from mininet.topo import Topo class ...

  10. [Eclipse]如何往eclipse中导入单个python文件,其它类型代码文件也可以参照该方法

    实例:想从外部单独拷一个文件到项目中指定路径,如果直接拷到对应文件夹路径下,启动eslipse又识别不到该文件,下面介绍直接copy的方法至eclipse,复制成功后即会在项目中对应路径下产生文件,下 ...