Android 进阶——轻量级跨进程传递Message利器Messenger详解
Posted CrazyMo_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 进阶——轻量级跨进程传递Message利器Messenger详解相关的知识,希望对你有一定的参考价值。
文章大纲
引言
作为android 开发者相信我们对于消息机制一定非常熟悉,对于进程内使用Handler处理Message 也一定了如执掌,而如果让你使用最简洁的方式实现进程间通信,也许有相当一部分初学者想到的是用AIDL自己实现,诚然思路是对的,但是还有更简单的机制供你使用。
一、Messenger 概述
Messenger是基于消息Message的传递的一种轻量级IPC进程间通信方式(通过在一个进程中创建一个指向Handler的Messenger,并将该Messenger传递给另一个进程),当然本质就是对Binder的封装(也是通过AIDL实现的 )。通过Messenger可以让我们可以简单地在进程间直接使用Handler进行Message传递,跨进程是通过Binder(AIDL实现),而消息发送是通过Handler#sendMessage方法,而处理则是Handler#handleMessage处理的;当然除了Handler之外还可以是自定义的相关的某些IBinder接口,简而言之,Messenger的跨进程能力是由构造时关联的对象提供的。
二、Messenger 源码解析
Messenger 实现了Parcelable接口,意味着自身可以跨进程传递,同时持有IMessenger 接口引用(一个Binder对象)意味着拿到这个Binder对象就可以跨进程使用。Messenger 只是把IMessenger接口包装起来并通过Binder进行跨进程传递,真正的核心能力提供者是IMessenger的实现类——android.os.Handler.MessengerImpl。
package android.os;
/**
* Reference to a Handler, which others can use to send messages to it.
* This allows for the implementation of message-based communication across
* processes, by creating a Messenger pointing to a Handler in one process,
* and handing that Messenger to another process.
*/
public final class Messenger implements Parcelable
private final IMessenger mTarget;
/**
* Create a new Messenger pointing to the given Handler. Any Message
* objects sent through this Messenger will appear in the Handler as if
* @link Handler#sendMessage(Message) Handler.sendMessage(Message) had been called directly.
*
* @param target The Handler that will receive sent messages.
*/
public Messenger(Handler target)
mTarget = target.getIMessenger();
/**
* Create a Messenger from a raw IBinder, which had previously been retrieved with @link #getBinder.
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target)
mTarget = IMessenger.Stub.asInterface(target);
/**
* Send a Message to this Messenger's Handler.
*
* @param message The Message to send. Usually retrieved through
* @link Message#obtain() Message.obtain().
*/
public void send(Message message) throws RemoteException
mTarget.send(message);
/**
* Retrieve the IBinder that this Messenger is using to communicate with
* its associated Handler.
* @return Returns the IBinder backing this Messenger.
*/
public IBinder getBinder()
return mTarget.asBinder();
public boolean equals(Object otherObj)
if (otherObj == null)
return false;
try
return mTarget.asBinder().equals(((Messenger)otherObj)
.mTarget.asBinder());
catch (ClassCastException e)
return false;
public int hashCode()
return mTarget.asBinder().hashCode();
public int describeContents()
return 0;
public void writeToParcel(Parcel out, int flags)
out.writeStrongBinder(mTarget.asBinder());
public static final Parcelable.Creator<Messenger> CREATOR
= new Parcelable.Creator<Messenger>()
public Messenger createFromParcel(Parcel in)
IBinder target = in.readStrongBinder();
return target != null ? new Messenger(target) : null;
public Messenger[] newArray(int size)
return new Messenger[size];
;
public static void writeMessengerOrNullToParcel(Messenger messenger,
Parcel out)
out.writeStrongBinder(messenger != null ? messenger.mTarget.asBinder()
: null);
public static Messenger readMessengerOrNullFromParcel(Parcel in)
IBinder b = in.readStrongBinder();
return b != null ? new Messenger(b) : null;
1、IMessenger接口
IMessenger是通过AIDL 自动生成的,一般在原生Android系统中I前缀的都是AIDL接口对应的实现类。对应的Messenger.aidl:
package android.os;
parcelable Messenger;
而IMessenger.aidl里就定义了一个入参为Message的方法 send(in Message msg)
package android.os;
import android.os.Message;
/** @hide */
oneway interface IMessenger
void send(in Message msg);
IMessenger.aidl对应的AIDL实现类:
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;
IMessenger就是一个Binder 接口只提供了一个方法——send 用于跨进程发送消息Message。
2、Messenger 主要方法
2.1、Messenger(Handler target)
public Messenger(Handler target)
mTarget = target.getIMessenger();
通过Handler构造Messenger时,就是调用了传入的Handler#getIMessenger()方法得到单例构造的MessengerImpl实例并初始化mTarget。
//Handler#getIMessenger()
final IMessenger getIMessenger()
synchronized (mQueue)
if (mMessenger != null)
return mMessenger;
mMessenger = new MessengerImpl();
return mMessenger;
继续往下追
private final class MessengerImpl extends IMessenger.Stub
public void send(Message msg)
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
本质就是通过Handler#sendMessage完成通信。
2.2、Messenger(IBinder target)
而通过IBinder对象构造Messenger时,就是把传入的IBinder对象“转成”MessengerImpl实例并初始化mTarget成员变量。
并非简单地直接强转而是先检索,如果已经创建过了就直接返回IBinder对应的代理对象,否则创建对应的代理对象再返回,预知详情请后续关注Binder系列文章。
public Messenger(IBinder target)
mTarget = IMessenger.Stub.asInterface(target);
2.3、send(Message message)
前面分析了send方法本质就是调用Handler#sendMessage方法,这也解释了为什么我们在服务端和客户端都需要创建Handler,因为需要在Handler去处理接收到的消息。
public void send(Message message) throws RemoteException
mTarget.send(message);//MessengerImpl#send
三、Messenger的使用
Messenger 基于Binder可以跨进程通信,为了方便我简单的把一个进程称之为服务端进程,另一个称之为客户端进程
1、首先在服务端定义一个Messenger对象
Messager.replyTo指向的客户端的Messenger,而Messenger又持有客户端的一个IBinder对象(即MessengerImpl),服务端正是利用这个IBinder对象做的与客户端的通信。
- 创建一个Handler
- 使用Handler初始化构建Messenger
package com.crazymo.messenger.rawmessenger;
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.util.Log;
public class MessengerService extends Service
public final static String TAG = "MessengerIPC";
public final static String KEY_NAME = "Name";
public final static String KEY_RESP = "Response";
public final static int MSG_WHAT_HELLO = 100;
public final static int MSG_WHAT_RESP = 1001;
/**
* 一个用于跨进程的序列化对象,包裹着IMessenger AIDL接口
*/
private static final Messenger messenger = new Messenger(new MessengerServerHandler());
private static class MessengerServerHandler extends Handler
@Override
public void handleMessage(Message msg)
doHandleMessage(msg);
/**
* 处理其他进程发过来的消息
* @param msg
*/
private static void doHandleMessage(Message msg)
if (msg != null)
String ret = "hello ";
//接收客户端的消息并处理
if (msg.what == MSG_WHAT_HELLO)
Log.e(TAG, "receive msg from client=" + msg.getData().getString(KEY_NAME));
try
Thread.sleep(1_000);
catch (InterruptedException e)
e.printStackTrace();
ret += msg.getData().getString(KEY_NAME);
//把处理结果封装到Message返回给客户端
Message reply = Message.obtain(null, MSG_WHAT_RESP);
Bundle bundle = new Bundle();
bundle.putString(KEY_RESP, ret);
reply.setData(bundle);
try
//msg.replyTo @ android.os.Messenger类型,Messager.replyTo指向的客户端的Messenger,而Messenger又持有客户端的一个Binder对象(MessengerImpl)。服务端正是利用这个Binder对象做的与客户端的通信。
if (msg.replyTo != null)
msg.replyTo.send(reply);
catch (RemoteException e)
e.printStackTrace();
else
Log.e(TAG, "handle client empty msg");
@Override
public IBinder onBind(Intent intent)
//返回Messenger的IBinder对象,当bindService 执行时候就会触发该回调,就可以拿到服务端的IBinder对象
return messenger.getBinder();
然后就在传入Handler#handleMessage 方法中实现处理消息的逻辑,至此一个远程Service实现完毕。
2、客户端使用Messenger
- 定义一个Handler 用于发送Message
- 初始化Messenger对象
package com.crazymo.messenger;
import android.annotation.SuppressLint;
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.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import com.crazymo.messenger.aidl.MyMessengerService;
import com.crazymo.messenger.rawmessenger.MessengerService;
public class MainActivity extends AppCompatActivity
private final static String TAG="MainActivity";
/***********************1、Messenger 方式****************************/
private Messenger mServer;
private ServiceConnection connMessenger =new ServiceConnection()
@Override
public void onServiceConnected(ComponentName name, IBinder service)
mServer=new Messenger(service);//把返回的IBinder对象初始化Messenger
Log.e(MessengerService.TAG, "MessengerService Connected!");
@Override
public void onServiceDisconnected(ComponentName name)
;
private final Handler handlerClient =new Handler()
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message msg)
if(msg!=null && msg.what== MessengerService.MSG_WHAT_RESP)
String resp=msg.getData().getString(MessengerService.KEY_RESP);
Log.e(MessengerService.TAG, "resp from server="+resp);
;
//为了接收服务端的回复,客户端也需要准备一个接收消息的Messenger 和Handler
private final Messenger clientMessenger=new Messenger(handlerClient);
private void bindMessengerService()
Intent intent=new Intent(this,MessengerService.class);
bindService(intent, connMessenger, Context.BIND_AUTO_CREATE);
public void sendByMessenger(View view)
Message msg=Message.obtain(null,MessengerService.MSG_WHAT_HELLO);
Bundle data=new Bundle();
data.putString(MessengerService.KEY_NAME,"CrazyMo_");
msg.setData(data);
//Client 发信时指定希望回信人,把客户端进程的Messenger对象设置到Message中
msg.replyTo=clientMessenger;
try
mServer.send(msg);//跨进程传递
catch (RemoteException e)
e.printStackTrace();
/***********************2、MyMessenger AIDL方式****************************/
private IMyMessenger myInterface;
private ServiceConnection connAidl = new ServiceConnection()
@Override
public void onServiceConnected(ComponentName name, IBinder service)
myInterface = IMyMessenger.Stub.asInterface(service);
Log.i(TAG, "MyMessenger 连接Service 成功");
@Override
public void onServiceDisconnected(ComponentName name)
Log.e(TAG, "连接Service失败");
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindMessengerService();
以上是关于Android 进阶——轻量级跨进程传递Message利器Messenger详解的主要内容,如果未能解决你的问题,请参考以下文章
Android 进阶——轻量级跨进程传递Message利器Messenger详解
Android AIDL Service 跨进程传递复杂数据