一、 摘要

本文介绍Android中的IPC方式之一——Messenger。


二、 关于Messenger

SDK中如此描述:

/**
 * 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.
 *
 * <p>Note: the implementation underneath is just a simple wrapper around
 * a {@link Binder} that is used to perform the communication.  This means
 * semantically you should treat it as such: this class does not impact process
 * lifecycle management (you must be using some higher-level component to tell
 * the system that your process needs to continue running), the connection will
 * break if your process goes away for any reason, etc.</p>
 */

大意是说,引用一个可以发送message的Handler。这允许基于message实现的跨进程通信,通过Handler创建一个Messanger,传递message到其他进程。需要注意的是,其实现仅仅是对Binder的简单包装。这意味着:Messenger不应该影响进程的生命周期管理(你必须用更高级别的组件来告诉系统你的进程需要继续执行),一旦你的进程因为任何原因中断,Messenger的连接也会断开。

整理出以下几个要点:

  • 通过Handler创建一个Messanger
  • Messenger基于Binder实现
  • 注意你的组件的生命周期

查看API文档,Messenger有两个构造方法:

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);
}

简单地理解Messanger,顾名思义就是一个信使,客户端和服务端之间不直接进行消息通信,而是通过信使来传达消息。


三、 编写一个Demo

1. 服务端

我们在Service中实现一个Messanger:

public class MessengerDemoService extends Service {
    private final static int MSG_RECEIVE_FROM_CLIENT_0 = 0;
    private final static int MSG_RECEIVE_FROM_CLIENT_1 = 1;
    private final static int MSG_REPLY_TO_CLIENT = 2;

    private final Messenger mMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_RECEIVE_FROM_CLIENT_0:
                    // 获取客户端发送的message中的数据
                    Bundle mBundle = msg.getData();
                    // TODO
                    break;
                case MSG_RECEIVE_FROM_CLIENT_1:
                    // 如果我们需要向客户端返回消息,则像这样:
                    Message msgReply = Message.obtain();
                    msgReply.what = MSG_REPLY_TO_CLIENT;
                    Bundle bundle = new Bundle();
                    // TODO 在bundle中放入回传数据
                    msgReply.setData(bundle);
                    try {
                        // msg.replyTo指向回传客户端的Messenger实例
                        msg.replyTo.send(msgReply);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    break;
            }
        }
    });

    @Override
    public IBinder onBind(Intent intent) {
        /**
         * 通过返回Messenger实例的binder来和Service进行绑定,
         * 当客户端向该Service发送message时,便通过binder将消息发送至Messenger实例,
         * 即最终将消息分发到Messenger实例的handleMessage方法中
         */
        return mMessenger.getBinder();
    }
}

然后在AndroidManifest中注册Service:

<service
    android:name=".MessengerDemoService"
     <!--表示允许其他应用调用我们这个Service-->
    android:exported="true">
</service>

2. 客户端

在客户端,我们需要声明两个Messenger,一个用来向服务端发送消息,一个用于接收服务端返回的消息。为什么在客户端不能像服务端那样直接使用replyTo的方式来回传呢?如果客户端和服务端都在接收消息后回传,两边可能就会一直传来传去,这样没完没了,程序就完了!并且按照C/S架构来讲,我们的两个Messenger分别对应request和response,而服务端收到request可能会进行response,如此描述,也就明白了吧。

我们在Activity中创建这两个Messenger实例:

public class MessengerDemoClient extends AppCompatActivity {
    private final static int MSG_RECEIVE_FROM_CLIENT_0 = 0;
    private final static int MSG_RECEIVE_FROM_CLIENT_1 = 1;
    private final static int MSG_REPLY_TO_CLIENT = 2;

    // 这是客户端用于接收服务端返回的Messenger
    private Messenger mClientMessenger = new Messenger(new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REPLY_TO_CLIENT:
                    // 获取客户端返回的message中的数据
                    Bundle mBundle = msg.getData();
                    // TODO
                    break;
                default:
                    break;
            }
        }
    });

    // 这是客户端用于向服务端发送消息的Messenger
    private Messenger mServerMessenger;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            /**
             * 这里用到了Messenger的IBinder构造方式,
             * 通过绑定Service的binder,我们的Messenger实例,
             * 便可以通过该binder向Service发送消息
             */
            mServerMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    /**
     * 我们需要在Activity创建时绑定Service,通常在onCreate中
     */
    private void bindService() {
        Intent intent = new Intent();
        // 如果我们给Service添加了用于启动的filter:
        intent.setAction("启动的filter");
        // TODO 使用setComponent或者setPackage来指定Service所在的应用
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    private void testSending() {
        Message msgSend = Message.obtain();
        msgSend.what = MSG_RECEIVE_FROM_CLIENT_1;
        Bundle bundle = new Bundle();
        // TODO 在bundle中放入传给服务端的数据
        msgSend.setData(bundle);
        // 指定我们这次发送消息的返回信息由mClientMessenger来处理
        msgSend.replyTo = mClientMessenger;
        try { 
            mServerMessenger.send(msgSend); 
        } catch (RemoteException e) { 
            e.printStackTrace(); 
        }
    }
}

最后别忘了检查我们的Activity是否在AndroidManifest中注册了。