跨进程通信之Messenger

   说起跨进程通信,很多人第一反应就是使用AIDL,不过今天我们要说的不是AIDL,而是底层使用了AIDL的Messenger。其实Messenger只是谷歌帮我们封装好了的AIDL,在Messenger中消息被一个一个地放到了队列中,也就是说Messenger一次只能处理一个请求,而不同考虑线程同步的问题,而AIDL中,请求可能会有几个同时到达,这是就要处理好线程同步的问题,所以使用Messenger会比较方便。为什么说Messenger是封装了的AIDL呢?看看Messenger的两个构造方法,大家就明白了。


public Messenger(Handler target) {
<span style="white-space:pre">	</span>mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
<span style="white-space:pre">	</span>mTarget = IMessenger.Stub.asInterface(target);
}


    无论是IMessenger还是Stub.asInterface,都表明了Messenger的底层是AIDL。接下来我们将围绕这两个方法来说说使用Messenger的客户端和服务端代码的一种简单写法。

   ·服务端:在客户端我们一般会创建一个Handler,在该Handler中handleMessage方法中处理来自客户端的消息,然后利用该Handler创建一个Messenger,最后在Service中onBind方法中返回该Messenger对象底层的Binder。代码如下:

private static class MessengerHandler extends Handler{
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public void handleMessage(Message msg) {
<span style="white-space:pre">	</span>switch (msg.what){
<span style="white-space:pre">		</span>case 0:
                Log.e(TAG, "receive msg from Client:" + msg.getData().getString("msg"));
                break;

            <span style="white-space:pre">	</span>default:
<span style="white-space:pre">		</span>super.handleMessage(msg);
<span style="white-space:pre">	</span>}
    }
}

private final Messenger mMessenger = new Messenger(new MessengerHandler());

<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public IBinder onBind(Intent intent) {
<span style="white-space:pre">		</span>return mMessenger.getBinder();
<span style="white-space:pre">	</span>}

     我们可以看到这里的Messenger是用了上面的第一种构造器来创建的,为什么要用这种构造器呢?我们得先知道,当传入Handler来创建Messenger时,这个Messenger就指向了参数中的Handler了,也就是说我们在服务端创建的Messenger已经和MessengerHanlder关联在一起了,通过该Messenger发送的信息将会在MessengerHanlder中处理。而我们又在onBind方法中返回了Messenger底层的Binder,相当于我们暴露了一个接口给客户端,客户端可以通过这个接口绑定到服务。

    ·注册服务:在接下去写客户端之前,别忘了在AndroidManifest文件中注册上面所写的service。

<service android:name="com.su.ipcdemo.service.MessengerService"
android:process=":remote"/>

       因为我是在同一个应用中实现跨进程通信,所以这里用了process属性让service在另一个进程执行,这和两个应用跨进程通信道理一样。这里要注意一个小细节,就是注册service时要写完整的包名,因为在没有任何<intent-filter>的情况下,因为跨进程,如果不写完整包名会找不到对应的service,从而绑定不了指定的service。

    ·客户端:在客户端第一步要做的就是绑定服务,然后利用该服务返回的IBinder对象创建一个Messenger(也就是利用上面所说的接口),然后通过该Messenger向服务端发送信息,最后在退出时要解除绑定的服务。具体代码如下:

Intent intent = new Intent(this, MessengerService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
<span style="white-space:pre">	</span>mService = new Messenger(service);
<span style="white-space:pre">	</span>Message msg = Message.obtain(null, 0);
<span style="white-space:pre">	</span>Bundle data = new Bundle();
<span style="white-space:pre">	</span>data.putString("msg","hello,this is client");
<span style="white-space:pre">	</span>msg.setData(data);
        try{
<span style="white-space:pre">		</span>mService.send(msg);
<span style="white-space:pre">	</span>}catch (RemoteException e){
            e.printStackTrace();
<span style="white-space:pre">		</span>}
   <span style="white-space:pre">	</span> }

<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public void onServiceDisconnected(ComponentName name) {

    <span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>};
<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>protected void onDestroy() {
    <span style="white-space:pre">		</span>unbindService(mConnection);
   <span style="white-space:pre">		</span> super.onDestroy();
<span style="white-space:pre">	</span>}

    bindService总共三个参数,第一个参数intent显示指明了要绑定的服务;第二个参数传入了mConnection,因为bindService是立即返回值的,不能接受服务端返回的IBinder,所以要用ServiceConnection来接收服务端返回的IBinder(也就是ServiceConnection方法的第二个参数),然后我们利用IBinder创建了Messenger(mService),然后发送消息给服务端,发送的消息将会在上面服务端所写的的MessengerHandler中被处理,这个效果看起来就像直接用服务端的Messenger发送消息一样;第三个参数传入了Context.BIND_AUTO_CREATE,因为服务是第一次被创建,所以要传入该值。
    通过bindService方法客户端已经成功绑定了服务端,最后记得在退出时调用unbindService接触绑定的服务。

    关于使用Messenger进行跨进程通信的简单例子已经讲解完了,希望我的总结能使看了该文章的你有一点点收获,如果有讲错的地方恳请指正。

    有关书籍:《Android开发艺术探索》




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值