#### 2.4.3 使用Messenger
**Messenger可以翻译为信使,顾名思义,通过它可以在不同进程中传递Message(信息)对象,在Message中放入我们需要传递的数据,就可以轻松地实现数据的进程间传递了**。
Messenger是一种**轻量级的IPC方案**,它的**底层实现是AIDL**,为什么这么说呢,我们大致看一下Messenger这个类的构造方法就明白了。下面是Messenger的两个构造方法,**从构造方法的实现上我们可以明显看出AIDL的痕迹,不管是IMessenger还是Stub.asInterface,这种使用方法都表明它的底层是AIDL**。
```
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
```
**Messenger的使用方法很简单,它对AIDL做了封装,使得我们可以更简便地进行进程间通信。同时,由于它一次处理一个请求,因此在服务端我们不用考虑线程同步的问题,这是因为服务端中不存在并发执行的情形**。
*****
总之:**Messenger是以串行的方式处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端仍然只能一个个处理,如果有大量的并发请求,那么用Messenger就不太合适了,同时,Messenger的作用主要是为了*传递消息*,很多时候我们可能需要跨进程调用服务端的方法,这种情形用Messenger就无法做到了**。
*****
实现一个Messenger有如下几个步骤,分为服务端和客户端,这里的可不是我们平常意义上的客户端和服务端,可以理解为两个进程。
**1.服务端进程**
首先,我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。
**2.客户端进程**
客户端进程中,首先要绑定服务端的Service(onCreate方法中调用bindService方法),绑定成功后用服务端返回的IBinder对象(ServiceConnection方法中返回)创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象。如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。
这听起来可能还是有点抽象,不过看了下面的两个例子,读者肯定就都明白了。首先,我们来看一个简单点的例子,在这个例子中服务端无法回应客户端。
首先看服务端的代码,这是服务端的典型代码,可以看到**MessengerHandler用来处理客户端发送的消息,并从消息中取出客户端发来的文本信息**。而**mMessenger是一个Messenger对象,它和MessengerHandler相关联,并在onBind方法中返回它里面的Binder对象**,可以看出,这里**Messenger的作用是将客户端发送的消息传递给MessengerHandler处理**。
* **服务端代码**
~~~
public class MessengerService extends Service {
private static final String TAG = "MessengerService";
//继承Handler,MessengerHandler用来处理客户端发送的消息,并从消息中取出客户端发来的文本信息。
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_CLIENT:
Log.i(TAG, "receive msg from Client:" + msg.getData().getString("msg"));
/**
* 因为我们的Messenger是通过客户端来获取的,而在客户端那边这个Messenger是以Handler为参数创建的,
* 所以在服务端通过客户端的Messenger发送消息后,在客户端的Handler就会处理这条消息,
* 嘻嘻,就达到了消息传送的目的。
*/
Messenger client = msg.replyTo;
Message relpyMessage = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply", "嗯,你的消息我已经收到,稍后会回复你。");
relpyMessage.setData(bundle);
try {
client.send(relpyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
//这是我们服务端自己的Messenger,它是以上面的Handler对象为参数创建的,
//这个Messenger是要通过绑定该服务器的时候onBind方法传递给客户端,然后客户端获取了该Messenger,
//再以该Messenger来发送消息,这样服务端就可以接收到该消息并处理。
private final Messenger mMessenger = new Messenger(new MessengerHandler());
//这个方法是在绑定服务的过程中调用的并将结果返回给客户端的,所以通过onBind方法客户端就可以获取我们Messenger的Binder对象了,
//然后客户端可以根据该Binder对象来创建一个Messenger,这样客户端中用的Messenger和这里的Messenger就是向对应的了。
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
~~~
然后,注册service,让其运行在单独的进程中:
```
<service
android:name="com.ryg.chapter_2.messenger.MessengerService"
android:process=":remote" >
```
接下来再看看客户端的实现,客户端的实现也比较简单,首先需要绑定远程进程的MessengerService,绑定成功后,根据服务端返回的binder对象创建Messenger对象并使用此对象向服务端发送消息。下面的代码在Bundle中向服务端发送了一句话,在上面的服务端代码中会打印出这句话。
**客户端代码**
```
public class MessengerActivity extends Activity {
private static final String TAG = "MessengerActivity";
private Messenger mService;
//准备一个接收消息的Messenger和Handler
//这是客户端自己的Messenger,传递给服务端,让服务端返回消息用的。
private Messenger mGetReplyMessenger = new Messenger (new MessengerHandler ());
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_SERVICE:
Log.i (TAG, "receive msg from Service:" + msg.getData ().getString ("reply"));
break;
default:
super.handleMessage (msg);
}
}
}
/**
* 这个是客户端用来绑定服务端用的,在绑定过程中会调用onServiceConnected,它的第二个参数IBinder service,
* 就是在服务端中onBind方法返回的结果,这个结果是服务端的Messenger对象的Binder对象,
* 然后客户端通过这个Binder对象就可以创建一个Messenger,
* 所以就是在绑定服务的过程中将服务端的Messenger传递给了客户端,建立起了两者之间的桥梁
*/
private ServiceConnection mConnection = new ServiceConnection () {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger (service);
Log.d (TAG, "bind service");
Message msg = Message.obtain (null, MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle ();
data.putString ("msg", "hello, this is client.");
msg.setData (data);
//把接收服务端回复的Messenger通过Message的replyTo参数传递给服务端
msg.replyTo = mGetReplyMessenger;
try {
mService.send (msg);
} catch (RemoteException e) {
e.printStackTrace ();
}
}
public void onServiceDisconnected(ComponentName className) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_messenger);
Intent intent = new Intent ("com.ryg.MessengerService.launch");
//在bindService的时候,服务端会通过onBind方法返回一个包含了服务端业务调用的Binder对象,
//通过这个对象,客户端就可以获取服务端提供的服务或者数据,
bindService (intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService (mConnection);
super.onDestroy ();
}
}
```
最后,我们运行程序,看一下log,很显然,服务端成功收到了客户端所发来的问候语:“hello, this is client.”。
```
I/MessengerService( 1037): receive msg from Client:hello, this is client.
```
通过上面的例子可以看出,**在Messenger(信使)中进行数据传递必须将数据放入Message(信息)中,而Messenger和Message都实现了Parcelable接口,因此可以跨进程传输**。简单来说,**Message中所支持的数据类型就是Messenger所支持的传输类型**。实际上,**通过Messenger来传输Message,Message中能使用的载体只有what、arg1、arg2、Bundle以及replyTo。Message中的另一个字段object在同一个进程中是很实用的,但是在进程间通信的时候,在Android 2.2以前object字段不支持跨进程传输,即便是2.2以后,也仅仅是系统提供的实现了Parcelable接口的对象才能通过它来传输。这就意味着我们自定义的Parcelable对象是无法通过object字段来传输的**,读者可以试一下。**非系统的Parcelable对象的确无法通过object字段来传输,这也导致了object字段的实用性大大降低**,所幸我们还有Bundle,**Bundle中可以支持大量的数据类型**。
上面的例子演示了如何在服务端接收客户端中发送的消息,但是有时候我们还需要能回应客户端,下面就介绍如何实现这种效果。还是采用上面的例子,但是稍微做一下修改,每当客户端发来一条消息,服务端就会自动回复一条“嗯,你的消息我已经收到,稍后会回复你。”,这很类似邮箱的自动回复功能。
首先看服务端的修改,服务端只需要修改MessengerHandler,当收到消息后,会立即回复一条消息给客户端。
```
//继承Handler,MessengerHandler用来处理客户端发送的消息,并从消息中取出客户端发来的文本信息。
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_CLIENT:
Log.i(TAG, "receive msg from Client:" + msg.getData().getString("msg"));
/**
* 因为我们的Messenger是通过客户端来获取的,而在客户端那边这个Messenger是以Handler为参数创建的,
* 所以在服务端通过客户端的Messenger发送消息后,在客户端的Handler就会处理这条消息,
* 嘻嘻,就达到了消息传送的目的。
*/
Messenger client = msg.replyTo;
Message relpyMessage = Message.obtain(null, MyConstants.MSG_FROM_SERVICE);
Bundle bundle = new Bundle();
bundle.putString("reply", "嗯,你的消息我已经收到,稍后会回复你。");
relpyMessage.setData(bundle);
try {
client.send(relpyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
default:
super.handleMessage(msg);
}
}
}
```
接着再看客户端的修改,为了接收服务端的回复,客户端也需要准备一个接收消息的Messenger和Handler,如下所示。
```
//准备一个接收消息的Messenger和Handler
//这是客户端自己的Messenger,传递给服务端,让服务端返回消息用的。
private Messenger mGetReplyMessenger = new Messenger (new MessengerHandler ());
private static class MessengerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyConstants.MSG_FROM_SERVICE:
Log.i (TAG, "receive msg from Service:" + msg.getData ().getString ("reply"));
break;
default:
super.handleMessage (msg);
}
}
}
```
除了上述修改,还有很关键的一点,当客户端发送消息的时候,需要把接收服务端回复的Messenger通过Message的replyTo参数传递给服务端,如下所示。
```
private ServiceConnection mConnection = new ServiceConnection () {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger (service);
Log.d (TAG, "bind service");
Message msg = Message.obtain (null, MyConstants.MSG_FROM_CLIENT);
Bundle data = new Bundle ();
data.putString ("msg", "hello, this is client.");
msg.setData (data);
//把接收服务端回复的Messenger通过Message的replyTo参数传递给服务端
msg.replyTo = mGetReplyMessenger;
try {
.send (msg);
} catch (RemoteException e) {
e.printStackTrace ();
}
}
public void onServiceDisconnected(ComponentName className) {
}
};
```
通过上述修改,我们再运行程序,然后看一下log,很显然,客户端收到了服务端的回复“嗯,你的消息我已经收到,稍后会回复你。”,这说明我们的功能已经完成。
```
I/MessengerService( 1419): receive msg from Client:hello, this is client.
I/MessengerActivity( 1404): receive msg from Service:嗯,你的消息我已经收到,
```
稍后会回复你。
到这里,我们已经把采用Messenger进行进程间通信的方法都介绍完了,读者可以试着通过Messenger来实现更复杂的跨进程通信功能。下面给出一张Messenger的工作原理图以方便读者更好地理解Messenger,如图2-6所示。
:-: ![](https://img.kancloud.cn/7f/9a/7f9afd1a086ab10578c59554d4f14dcc_1437x530.png)
图2-6 Messenger的工作原理
关于进程间通信,可能有的读者会觉得笔者提供的示例都是针对同一个应用的,有没有针对不同应用的?是这样的,之所以选择在同一个应用内进行进程间通信,是因为操作起来比较方便,但是效果和在两个应用间进行进程间通信是一样的。在本章刚开始就说过,**同一个应用的不同组件,如果它们运行在不同进程中,那么和它们分别属于两个应用没有本质区别**,关于这点需要深刻理解,因为这是理解进程间通信的基础。
- 前言
- 第1章 Activity的生命周期和启动模式
- 1.1 Activity的生命周期全面分析
- 1.1.1 典型情况下的生命周期分析
- 1.1.2 异常情况下的生命周期分析
- 1.2 Activity的启动模式
- 1.2.1 Activity的LaunchMode
- 1.2.2 Activity的Flags
- 1.3 IntentFilter的匹配规则
- 第2章 IPC机制
- 2.1 Android IPC简介
- 2.2 Android中的多进程模式
- 2.2.1 开启多进程模式
- 2.2.2 多进程模式的运行机制
- 2.3 IPC基础概念介绍
- 2.3.1 Serializable接口
- 2.3.2 Parcelable接口
- 2.3.3 Binder
- 2.4 Android中的IPC方式
- 2.4.1 使用Bundle
- 2.4.2 使用文件共享
- 2.4.3 使用Messenger
- 2.4.4 使用AIDL
- 2.4.5 使用ContentProvider
- 2.4.6 使用Socket
- 2.5 Binder连接池
- 2.6 选用合适的IPC方式
- 第3章 View的事件体系
- 3.1 View基础知识
- 3.1.1 什么是View
- 3.1.2 View的位置参数
- 3.1.3 MotionEvent和TouchSlop
- 3.1.4 VelocityTracker、GestureDetector和Scroller
- 3.2 View的滑动
- 3.2.1 使用scrollTo/scrollBy
- 3.2.2 使用动画
- 3.2.3 改变布局参数
- 3.2.4 各种滑动方式的对比
- 3.3 弹性滑动
- 3.3.1 使用Scroller7
- 3.3.2 通过动画
- 3.3.3 使用延时策略
- 3.4 View的事件分发机制
- 3.4.1 点击事件的传递规则
- 3.4.2 事件分发的源码解析
- 3.5 View的滑动冲突
- 3.5.1 常见的滑动冲突场景
- 3.5.2 滑动冲突的处理规则
- 3.5.3 滑动冲突的解决方式
- 第4章 View的工作原理
- 4.1 初识ViewRoot和DecorView
- 4.2 理解MeasureSpec
- 4.2.1 MeasureSpec
- 4.2.2 MeasureSpec和LayoutParams的对应关系
- 4.3 View的工作流程
- 4.3.1 measure过程
- 4.3.2 layout过程
- 4.3.3 draw过程
- 4.4 自定义View
- 4.4.1 自定义View的分类
- 4.4.2 自定义View须知
- 4.4.3 自定义View示例
- 4.4.4 自定义View的思想
- 第5章 理解RemoteViews
- 5.1 RemoteViews的应用
- 5.1.1 RemoteViews在通知栏上的应用
- 5.1.2 RemoteViews在桌面小部件上的应用
- 5.1.3 PendingIntent概述
- 5.2 RemoteViews的内部机制
- 5.3 RemoteViews的意义
- 第6章 Android的Drawable
- 6.1 Drawable简介
- 6.2 Drawable的分类
- 6.2.1 BitmapDrawable2
- 6.2.2 ShapeDrawable
- 6.2.3 LayerDrawable
- 6.2.4 StateListDrawable
- 6.2.5 LevelListDrawable
- 6.2.6 TransitionDrawable
- 6.2.7 InsetDrawable
- 6.2.8 ScaleDrawable
- 6.2.9 ClipDrawable
- 6.3 自定义Drawable
- 第7章 Android动画深入分析
- 7.1 View动画
- 7.1.1 View动画的种类
- 7.1.2 自定义View动画
- 7.1.3 帧动画
- 7.2 View动画的特殊使用场景
- 7.2.1 LayoutAnimation
- 7.2.2 Activity的切换效果
- 7.3 属性动画
- 7.3.1 使用属性动画
- 7.3.2 理解插值器和估值器 /
- 7.3.3 属性动画的监听器
- 7.3.4 对任意属性做动画
- 7.3.5 属性动画的工作原理
- 7.4 使用动画的注意事项
- 第8章 理解Window和WindowManager
- 8.1 Window和WindowManager
- 8.2 Window的内部机制
- 8.2.1 Window的添加过程
- 8.2.2 Window的删除过程
- 8.2.3 Window的更新过程
- 8.3 Window的创建过程
- 8.3.1 Activity的Window创建过程
- 8.3.2 Dialog的Window创建过程
- 8.3.3 Toast的Window创建过程
- 第9章 四大组件的工作过程
- 9.1 四大组件的运行状态
- 9.2 Activity的工作过程
- 9.3 Service的工作过程
- 9.3.1 Service的启动过程
- 9.3.2 Service的绑定过程
- 9.4 BroadcastReceiver的工作过程
- 9.4.1 广播的注册过程
- 9.4.2 广播的发送和接收过程
- 9.5 ContentProvider的工作过程
- 第10章 Android的消息机制
- 10.1 Android的消息机制概述
- 10.2 Android的消息机制分析
- 10.2.1 ThreadLocal的工作原理
- 10.2.2 消息队列的工作原理
- 10.2.3 Looper的工作原理
- 10.2.4 Handler的工作原理
- 10.3 主线程的消息循环
- 第11章 Android的线程和线程池
- 11.1 主线程和子线程
- 11.2 Android中的线程形态
- 11.2.1 AsyncTask
- 11.2.2 AsyncTask的工作原理
- 11.2.3 HandlerThread
- 11.2.4 IntentService
- 11.3 Android中的线程池
- 11.3.1 ThreadPoolExecutor
- 11.3.2 线程池的分类
- 第12章 Bitmap的加载和Cache
- 12.1 Bitmap的高效加载
- 12.2 Android中的缓存策略
- 12.2.1 LruCache
- 12.2.2 DiskLruCache
- 12.2.3 ImageLoader的实现446
- 12.3 ImageLoader的使用
- 12.3.1 照片墙效果
- 12.3.2 优化列表的卡顿现象
- 第13章 综合技术
- 13.1 使用CrashHandler来获取应用的crash信息
- 13.2 使用multidex来解决方法数越界
- 13.3 Android的动态加载技术
- 13.4 反编译初步
- 13.4.1 使用dex2jar和jd-gui反编译apk
- 13.4.2 使用apktool对apk进行二次打包
- 第14章 JNI和NDK编程
- 14.1 JNI的开发流程
- 14.2 NDK的开发流程
- 14.3 JNI的数据类型和类型签名
- 14.4 JNI调用Java方法的流程
- 第15章 Android性能优化
- 15.1 Android的性能优化方法
- 15.1.1 布局优化
- 15.1.2 绘制优化
- 15.1.3 内存泄露优化
- 15.1.4 响应速度优化和ANR日志分析
- 15.1.5 ListView和Bitmap优化
- 15.1.6 线程优化
- 15.1.7 一些性能优化建议
- 15.2 内存泄露分析之MAT工具
- 15.3 提高程序的可维护性