Android进阶笔记04:Android进程间通讯(IPC)之Messenger
一、 Android进程间通讯之Messenger 的引入
(1)引言:
平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都可以进行进程间通讯。它是基于消息的进程间通信,就像子线程和UI线程发送消息那样,是不是很简单,还不用去写AIDL文件,是不是有点小爽。哈哈。此外,还支持记录客户端对象的Messenger,然后可以实现一对多的通信;甚至作为一个转接处,任意两个进程都能通过服务端进行通信。
(2) Messenger 与 AIDL 比较:
当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。
Messenger 是以串行的方式处理客户端发来的消息的,这样一来,如果大量的消息同时发送到服务端,服务端仍然只能一个个处理,如果存在大量并发请求,那么使用Messenger就不太合适了。同时,Messenger的作用主要是为了传递消息,很多时候我们可能需要跨进程调用服务端的方法。这种情形用Messenger是无法做到的,但是我们可以使用AIDL来实现跨进程的方法调用。
Messenger的底层实现是AIDL,因此Messenger本质上也是AIDL,只不过系统为我们做了封装从而方便上层调用而已。
对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。
二、 Messenger 的具体使用:
1. Messenger工作原理图:
2. 客户端发送消息给服务端(单向通信)
服务端:
(1)创建一个handler对象,并实现handlemessage方法,用于接收来自客户端的消息,并作处理 .
(2)创建一个messenger(送信人),封装handler .
(3)messenger创建一个IBinder对象,通过onBind返回给客户端
客户端:
(1)在activity中绑定服务
(2)创建ServiceConnection并在其中使用 IBinder 将 Messenger实例化
(3)使用Messenger向服务端发送消息
(4)解绑服务
(5)服务端中在 handleMessage() 方法中接收每个 Message
这样,客户端并没有调用服务的"方法"。而客户端传递的"消息"(Message 对象)是服务在其 Handler 中接收的。
上面实现的仅仅是单向通信,即客户端给服务端发送消息。
3. 客户端与服务端双向通信
如果我需要服务端给客户端发送消息又该怎样做呢?
其实,这也是很容易实现的,下面就让我们接着上面的步骤来实现双向通信吧:
(1)在客户端中创建一个Handler对象,用于处理服务端发过来的消息。
(2)创建一个客户端自己的messenger对象,并封装handler。
(3)将客户端的Messenger对象赋给待发送的Message对象的replyTo字段。
(4)在服务端的Handler处理Message时将客户端的Messenger解析出来,并使用客户端的Messenger对象给客户端发送消息。
这样就实现了客户端和服务端的双向通信了。
注意:
注:Service在声明时必须对外开放,即android:exported="true"
是不是看的头晕,忘掉吧,直接看下面。
三、代码示例:
(1)服务端service:
public class MyService extends Service {
private static final int CODE = 1;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
} //创建一个送信人,封装handler
private Messenger mMessenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
Message toClient = Message.obtain();
switch (msg.what) {
case CODE:
//接收来自客户端的消息,并作处理
int arg = msg.arg1;
Toast.makeText(getApplicationContext(),arg+"" , Toast.LENGTH_SHORT).show();
toClient.arg1 = 1111111111;
try {
//回复客户端消息
msg.replyTo.send(toClient);
} catch (RemoteException e) {
e.printStackTrace();
}
}
super.handleMessage(msg);
}
});
}
此外,还应该在AndroidManifest.xml中指定如下:
<service android:name=".MessengerService"
android:process=":remote"></service>
(2)客户端
package com.zixue.god.fuck; import android.content.ComponentName;
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.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast; public class MainActivity extends AppCompatActivity {
private boolean mBond;
private Messenger serverMessenger;
private MyConn conn; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定服务
Intent intent = new Intent();
intent.setAction("com.zixue.god.myapplication.server");
conn = new MyConn();
bindService(intent, conn, BIND_AUTO_CREATE);
Button button = (Button) findViewById(R.id.bt);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message clientMessage = Message.obtain();
clientMessage.what = 1;
clientMessage.arg1 = 12345;
try {
clientMessage.replyTo = mMessenger;
serverMessenger.send(clientMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
} private class MyConn implements ServiceConnection { @Override
public void onServiceConnected(ComponentName name, IBinder service) {
//连接成功
serverMessenger = new Messenger(service);
Log.i("Main", "服务连接成功");
mBond = true;
} @Override
public void onServiceDisconnected(ComponentName name) {
serverMessenger = null;
mBond = false;
}
} // 1 为客户端实例化一个Messenger,用于处理从服务端传递过来的数据
private Messenger mMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(),msg.arg1+"",Toast.LENGTH_SHORT).show();
super.handleMessage(msg);
}
}); @Override
protected void onDestroy() {
if (mBond) {
unbindService(conn);
}
super.onDestroy();
} }
客户端也比较简单,在onCreate方法中,进行绑定服务(注意:这种方式前面说过了,不应该在主线程进行IPC操作,因为这是耗时的,这里为了方便才写在主线程)。然后在onServiceConnected()中,利用返回的service创建了一个Messenger,然后执行一系列的数据打包、存放、发送操作。
(3)总结:
1)传递的数据必须是Bundle所支持的数据类型,如果是新的数据类型必须实现Parcelable接口或者Serializable接口。
2)接受消息的一端必须要有一个处理消息的Handler,Handler通常作为参数用于实例化一个Messenger。
3)如果服务端需要返回数据给客户端,那么在客户端中,需要把客户端自己的Messenger传递进msg.replyTo,这样服务器才能从msg.replyTo中取出特定的Messenger,从而返回信息。
4)在一次完整的进程间通讯(包括客户端的收发和服务端的收发)中,使用了两个不同的Messenger,第一个Messenger是用服务端返回的IBinder对象进行实例化的,这个用于从客户端发送数据到服务端;第二个Messenger是Handler实例化的,这个用于从服务端发送数据到客户端。
Android进阶笔记04:Android进程间通讯(IPC)之Messenger的更多相关文章
- Android AIDL 进行进程间通讯(IPC)
编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...
- High Performance Networking in Google Chrome 进程间通讯(IPC) 多进程资源加载
小结: 1. 小文件存储于一个文件中: 在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里.其中有索引文件(在浏览器启动时加载到内存中),数据文件( ...
- QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开 本文地址:h ...
- 服务 远程服务 AIDL 进程间通讯 IPC
Activity aidl接口文件 package com.bqt.aidlservice; interface IBinderInterface { /* 更改文件后缀为[.aidl]去掉 ...
- 服务 进程间通讯 IPC AIDL Parcelable 简介
1.IBinder和Binder是什么鬼? 我们来看看官方文档怎么说: 中文翻译: IBinder是远程对象的基本接口,是为了高性能而设计的轻量级远程调用机制的核心部分. 但他不仅用于远程调用,也用 ...
- 服务 远程服务 AIDL 进程间通讯 IPC 深化
示例 aidl接口文件 package com.bqt.aidlservice.aidl; parcelable Person; package com.bqt.aidlservice.aidl; ...
- 进程间通讯IPC的几种方式总结
Linux进程间的通讯 Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同.前者对Unix早期的进程间通信 ...
- Android进阶笔记18:选用合适的IPC方式
1. 相信大家都知道Android进程间通信方式很多,比如AIDL.Messenger等等,接下来我就总结一下这些IPC方式优缺点. 2. IPC方式的优缺点和适用场景 3. 附加:使用Intent实 ...
- Android进阶笔记15:选用合适的IPC方式
1. 相信大家都知道Android进程间通信方式很多,比如AIDL.Messenger等等,接下来我就总结一下这些IPC方式优缺点. 2. IPC方式的优缺点和适用场景 3. 附加:使用Intent实 ...
随机推荐
- HDU 5289 Assignment
题意:求一段长度为n的序列里有多少个子区间内的最大值减最小值小于k. 解法:RMQ+尺取法或单调队列.RMQ可以用st或者线段树,尺取法以前貌似YY出来过……只是不知道是这个东西…… 设两个标记l和r ...
- 2、Android应用程序基本特性
1. apk是android应用程序安装格式,.dex是Android二进制执行文件格式. 2.Android操作系统是基于Linux的多用户操作系统,每一个应用程序都是使用的不同的用户. 3. 默认 ...
- redis-3.0.0集群的安装及使用
redis集群需要至少6个节点(偶数节点),3个主节点,3个从节点.注意:集群模式最好不要keys *查询数据. 1 下载redis,官网下载3.0.0版本,之前2.几的版本不支持集群模式.下载地址: ...
- Action 操作
当鼠标移动到图片文件夹的时候,将有一些button显示 当鼠标移开这个文件夹,那些button隐藏了起来 display属性的变化 1.可以使用Js改变属性来操作 暂未验证,待时间. 2.可以使用Ac ...
- iOS7程序后台运行
介绍 这次 iOS7 对程序后台运行进行了加强,但是仅仅是加强而已,要想像 Android 程序那样自由当然就别想了,苹果这么做主要还是出于电池使用时间考虑,但是这次的加强对大部分程序基本够用. 在介 ...
- opencv 在工业中的应用:二维标定
在工业中经常要检测一个零件的尺寸,但是图像处理得到的是像素值,怎么才能得到实际的毫米值呢?这就要用到二维标定,我用OPENCV写了一个利用标定板进行标定的DEMO. 很多商业软件都没有二维标定的功能, ...
- jquery优化28个建议
我一直在寻找有关jQuery性能优化方面的小窍门,能让我那臃肿的动态网页应用变得轻便些.找了很多文章后,我决定将最好最常用的一些优化性能的建议列出来.我也做了一个jQuery性能优化的简明样式表,你可 ...
- Leetcode OJ : Merge k Sorted Lists 归并排序+最小堆 mergesort heap C++ solution
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...
- ASIHTTPRequest 编码问题
今天在模拟登陆时,中文的用户名一直登陆不上,对用户名进行了各种转码还是不能解决. 在这个问题上一直卡了半个多小时,最终才发现根本不是用户名的编码问题,而是使用的第三方网络插件的ASIHTTPReque ...
- hdu5792--World is Exploding
题意:给一个数列,求四个各不相同的数,一个逆序对,一个正序对,求多少组这样的四个数. 题解:辣鸡如我,还是上官方题解了. rg(i)就是i右边比i大的数的个数,rs(i)就是i右边比i小的数的个数. ...