进程间通信IPC

IPC是“Inter-Process Communication”的缩写,即进程间通信。Android为APP提供了多进程工作模式,这是因为多线程存在若干局限:
1、多线程共存于一个进程中,而该进程可用的内存容量是固定的,多线程不会拓展app可用的内存大小。所以如果app的性能瓶颈在内存,那么多线程并不能提高处理速度。
2、app在响应用户操作之外,还想完成某些系统管理的任务,比如说双守护进程防止被意外杀掉、比如说app集成第三方插件要定期推送消息,以及其他类似服务端系统管理的功能。
另外,进程间通信不局限于两个APP进程直接通信,也包括APP与系统进程通信,以及进程间通过文件、广播等手段间接通信。

开启多进程

APP开启多进程需要同时修改配置和代码。

配置修改
在AndroidManifest.xml给service节点增加process属性,表示该服务运行在指定进程上。process属性有两种赋值方式:
1、使用相对路径,在进程名前加冒号:android:process=":another"。该方式表示指定服务运行于名称为“当前包名:another”。如果当前包名为“com.example.exmprocess”,那么服务运行的进程名是“com.example.exmprocess:another”
2、使用绝对路径:com.example.exmprocess.another。该方式表示指定服务运行于名称为“com.example.exmprocess.another”。
这两种方式除了命名上的区别,还有权限上的区别。前一种方式表示该进程是私有的,只有本APP的其它进程才能访问它。后一种方式表示该进程是公共的,其他APP只要声明拥有它的权限,那么其他APP也可以与之通信。

代码修改
多进程模式下启动服务,只能通过bindService来启动,不能通过startService来启动。在《 Android开发笔记(四十一)Service的生命周期》中,我们知道bindService是先启动一个服务,然后再绑定它;而startService是直接在主线程中开启服务,所以start方式不能用于多进程模式。
进程间通信除了借助于Handler,还得叫来信使Messenger来帮忙,Messenger担负着传递请求消息与应答消息的重任。

信使Messenger

在之前的《 Android开发笔记(四十八)Thread类实现多线程》,博主提到Message的replyTo字段只用于跨进程通信,下面再具体说明Message在多线程和多进程模式下的区别:
1、obj字段:只可用于线程间通信,不可用于进程间通信。因为Messenger是个Parcelable对象,而obj是Object类型,无法进行序列化。
2、replyTo字段:只用于进程间通信。存放的是应答信使的对象。
3、setData和getData方法:进程间通信只能通过setData发送消息、getData获取消息,因为Bundle继承自Parcelable。线程间通信也可使用这两个方法。

下面是Messenger的常用方法:
Messenger(Handler target) : 构造函数,传入当前进程的Handler对象。该方式创建了一个持有当前进程实例的本地信使,本地信使会收到并处理消息。
Messenger(IBinder target) : 构造函数,传入对方进程的IBinder对象。该方式创建了一个持有对方进程实例的远程信使,远程信使只能向对方进程发送消息。
send : 发送消息。用于客户端向服务端发送请求消息,以及服务端向客户端发送应答消息。
getBinder : 获得当前信使的IBinder,一般用在服务的onBind方法中返回IBinder对象。

为方便记忆Messenger的工作流程,博主经过测试得出了下列三个场景的消息传递流程:
绑定信使的流程: 客户端bindService->服务端onCreate(根据Handler构造接收信使)->onBind(调用getBinder方法返回IBinder)->客户端onServiceConnected(根据IBinder构造发送信使)
请求信息发送/接收的流程:客户端准备(根据Handler构造应答信使)->发送信使send(传入信息内容与应答信使)->服务端handleMessage(根据replyTo构造反馈信使与数据处理)
应答信息返回/完成的流程:服务端反馈信使send->客户端handleMessage(数据处理)

IBinder

下面这段介绍翻译自Android的开发文档:IBinder是远程对象的基本接口,是为高性能而设计的轻量级远程调用机制的核心部分。但它不仅用于远程调用,也用于进程内调用。这个接口定义了与远程对象交互的协议。不要直接实现这个接口,而应该从Binder派生。简而言之,Android的跨进程通信是通过IBinder实现的。
使用Messenger传达IBinder对象的目的之一,是onServiceConnected方法中如果服务运行于另外一个进程,则不能对IBinder对象直接强制转换类型,否则会报错“java.lang.ClassCastException: android.os.BinderProxy cannot be cast to...”。如果FirstService声明了运行于单独进程“android:process=":message"”,则下面这个代码在类型转换时就会抛出异常:

    private FirstService mFirstService;private ServiceConnection mFirstConn = new ServiceConnection() {public void onServiceConnected(ComponentName name, IBinder service) {mFirstService = ((FirstService.LocalBinder) service).getService();}public void onServiceDisconnected(ComponentName name) {mFirstService = null;}};

IBinder的主要API是transact(),与它对应另一方法是Binder.onTransact()。第一个方法使你可以向远端的IBinder对象发送请求,第二个方法使你自己的远程对象能够接收响应。IBinder的API都是同步执行的,比如transact()直到对方的Binder.onTransact()方法调用完成后才返回。

在操作远程对象时,若要查看它们是否有效,有三种方法可以使用:
1、transact:该方法将在IBinder所在的进程不存在时抛出RemoteException异常。
2、pingBinder:如果目标进程不存在,那么调用该方法时将返回false。
3、linkToDeath:通过该方法向IBinder注册一个IBinder.DeathRecipient,在IBinder代表的进程退出时被调用。

Messenger方式一般不需要重写IBinder。

使用示例

下面是多进程模式MessageService的示例代码:

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;public class MessageService extends Service {private static final String TAG = "MessageService";private Messenger mRecvMsg;private Messenger mReplyMsg;private Bundle mBundle;Handler mServerHandler = new Handler(){public void handleMessage(Message msg) {mReplyMsg = msg.replyTo;mBundle = msg.getData();new ReplyThread().start();}};class ReplyThread extends Thread {public void run() {String desc = String.format("请求参数为%s,应答参数为%s", mBundle.getString("msg"), "bbb");Bundle bundle = new Bundle();bundle.putString("msg", desc);Message msg = Message.obtain();msg.setData(bundle);try {mReplyMsg.send(msg);} catch (RemoteException e) {e.printStackTrace();}}}@Overridepublic void onCreate() {mRecvMsg = new Messenger(mServerHandler);super.onCreate();}@Overridepublic IBinder onBind(Intent intent) {return mRecvMsg.getBinder();}}

下面是主进程调用服务的代码:

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
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.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;public class MessengerActivity extends Activity implements OnClickListener {private static final String TAG = "MessengerActivity";private TextView tv_process;private Messenger mSendMsg;private Messenger mReplyMsg;Handler mClientHandler = new Handler(){public void handleMessage(Message msg) {Bundle bundle = msg.getData();tv_process.setText(bundle.getString("msg"));}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_messenger);tv_process = (TextView) findViewById(R.id.tv_process);Button btn_messenger_start = (Button) findViewById(R.id.btn_messenger_start);btn_messenger_start.setOnClickListener(this);mReplyMsg = new Messenger(mClientHandler);Intent intent = new Intent(this, MessageService.class);bindService(intent, mMessageConn, Context.BIND_AUTO_CREATE);}private ServiceConnection mMessageConn = new ServiceConnection() {public void onServiceConnected(ComponentName name, IBinder binder) {mSendMsg = new Messenger(binder);}public void onServiceDisconnected(ComponentName name) {}};@Overridepublic void onClick(View v) {if (v.getId() == R.id.btn_messenger_start) {Bundle bundle = new Bundle();bundle.putString("msg", "aaa");Message msg = Message.obtain();msg.setData(bundle);msg.replyTo = mReplyMsg;try {mSendMsg.send(msg);} catch (RemoteException e) {e.printStackTrace();}}}}

点此查看Android开发笔记的完整目录

Android开发笔记(五十一)通过Messenger实现进程间通信相关推荐

  1. Android开发笔记(十一)自定义视图的构造方法

    自定义视图的用法 Android自带的视图常常不能满足实际开发的需求,这种情况下我们就得自定义视图(View). 首先在res\values目录下找到attrs.xml(如没有则创建之),在该属性定义 ...

  2. Android开发笔记(序)写在前面的目录

    知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面希望通过分享自己的经验教训,与网友互相切磋,从而去芜存菁进一步提升自己的水平.因此博主就想,入门的东西咱就不写了,人不能老停留在入 ...

  3. Android开发笔记(序)

    本开发笔记,借鉴与其他开发者整理的文章范例与心得体会.在这里作为开发过程中的一个总结与笔记式记录. 如有侵犯作者权益,请及时联系告知删除.俗话说:集百家成一言,去粕成金. ************** ...

  4. Android开发笔记(序)写在前面的目录大全

    转自  湖前琴亭 的博客https://blog.csdn.net/aqi00/article/details/50012511 知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面 ...

  5. Andriod开发之二十:Android开发笔记(序)写在前面的目录

    https://blog.csdn.net/aqi00/article/details/50038385 知识点分类 一方面写写自己走过的弯路掉进去的坑,避免以后再犯:另一方面希望通过分享自己的经验教 ...

  6. Android开发笔记(一百五十一)WebView与JavaScript交互的四种形式

    WebView如果作为简单的网页浏览器,对于一般的浏览行为来说,已经足够了.可做为企业开发者,你的App通常要嵌入自家公司的网页,如此一来,还得考虑App与Web之间的消息传递,这就涉及到App的原生 ...

  7. Android开发笔记(五十四)数据共享接口ContentProvider

    ContentProvider 前面几节介绍了进程间通信的几种方式,包括消息包级别的Messenger.接口调用级别的AIDL.启动页面/服务级别的Notification,还有就是本节这个数据库级别 ...

  8. Android开发笔记(五十三)远程接口调用AIDL

    AIDL概述 AIDL全称是"Android Interface Definition Language",即Android的接口定义语言.AIDL用来协助开发者来处理进程间通信, ...

  9. Android开发笔记(六十一)文件下载管理DownloadManager

    下载管理DownloadManager 文件下载其实是网络数据访问的一种特殊形式,使用普通的http请求也能完成,就是实现起来会繁琐一些.因为下载功能比较常用,而且业务功能相对统一,所以从Androi ...

最新文章

  1. Eclipse 中修改android的Default debug keystore 搬家、备份后启动Android PANIC :Could not open D:\java2\android\and
  2. messagebox 全部使用_商业篇 | 使用python开发性格分析工具卖钱
  3. 小牛485通讯原理_plc和变频器通讯接线图详解
  4. 可怜的 JavaScript,他们说你很怪异,你知道吗?
  5. 父类指针指向子类实例,用父类指针调用虚函数,调用的是子类的函数还是父类的函数...
  6. 在的微型计算机系统中 外设可和,微机原理第七章题库
  7. 20. jQuery 遍历 - 祖先
  8. 为什么要使用Keil MDK-ARM中间件库?
  9. 基于Socket实现网络编程
  10. 海康威视摄像头录制的视频无法用PR剪辑
  11. wifi已连接不可上网服务器无响应,wifi已连接不可上网是什么原因?
  12. vs2015 :“64位调试操作花费的时间比预期要长“,无法运行调试解决办法
  13. 本地搭建wooyun图片无法加载问题解决
  14. 感恩节,感谢大家的一路相伴
  15. Adobe photo shop 裁剪某个图层中图片的大小
  16. elasticsearch从入门到入门系列(二)---快速入门A
  17. Yii学习--使用Yii来建立博客
  18. 土壤湿度使用详细教程(基于树莓派3b+)
  19. 966. Vowel Spellchecker
  20. 用一个原始密码针对不同软件生成不同密码并保证相对安全

热门文章

  1. 蓝桥杯 基础练习 2n皇后问题(从n皇后问题入手)
  2. TensorFlow2.0:常用数据范围压缩函数
  3. TensorFlow2.0:数据统计
  4. sitemap.xml生成方法(asp和php)(转)
  5. Selenium模拟JQuery滑动解锁
  6. 计算机专业答辩开场白,毕业答辩开场白三分钟
  7. Linux FTP服务安装与账号设置
  8. JSP自定义标签入门实例
  9. html表格td点击事件,监听layui中的table中的td点击事件
  10. java设置界面边框,技术员教你解决Java 添加Word页面边框