千里马Android Framework实战开发-binder通信之Messenger介绍

Posted Android高级知识分享官

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了千里马Android Framework实战开发-binder通信之Messenger介绍相关的知识,希望对你有一定的参考价值。

csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论

android跨进程通信实战视频课程(加群获取优惠)

Messenger是什么?

Messenger是基于AIDL实现的轻量级IPC方案。
这里立马就会有疑问为什么要它呢?明明有了aidl
上节课大家学完了aidl进行binder通信是否感觉到使用起来其实还是有点复杂,毕竟通信什么的要写aidl,而且客户端和服务端都需要aidl文件,两个过程里面都需要,相对来说还是比较麻烦,对于项目过程中可能就是一些简单的跨进程数据传递,就是调用几个非常非常简单的方法,很多觉得都要写aidl成本比较大,那么有没有更加简单的方案来解决这个问题呢?
那就是本节课要讲解的Messenger。
那么接下来直接讲他的使用过程:

1、服务端对Messenger的使用

服务端需要实现一个Handler用于处理客户端发来的跨进程通信信息:

 Handler messengerHandler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what) {
                case  1:
                    Log.i("test","MessengerService Messenger handleMessage msg = " + msg + " bundle  key value = " + msg.getData().getString("bundleKey"));
                    Messenger clientSend = msg.replyTo;
                    Message toClientMsg = Message.obtain();
                    toClientMsg.what = 2;
                   // toClientMsg.obj = "I am replay from Server";
                    try {
                        clientSend.send(toClientMsg);
                    }catch (Exception e) {
                        Log.i("test","MessengerService clientSend  error ",e);
                    }
                    break;
            }
            super.handleMessage(msg);
        }
    };

其次服务端构造出对应的Messenger:
服务端构造:
Messenger messenger = new Messenger(messengerHandler);
注意这里参数是messengerHandler即一个Handler

最后,当服务端的onBinder回调时候要返回Messenger的IBinder对象给客户端

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }

2、客户端的使用

客户端还是和以前一样通过bindService在ServiceConnection类的onServiceConnected获取到服务端的返回的IBinder,从而获取到服务端的Messenger代理类,调用send函数发送Message。所以Messenger能发送的信息只有Message能携带的信息。

Intent intent = new Intent(MainActivity.this,MessengerService.class);
                Log.i("test","MessengerService  onClick ");
                bindService(intent, new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName name, IBinder service) {
                        try {
                            Log.i("test","MessengerService  onServiceDisconnected name = " +name);
                            messengerServer = new Messenger(service);
                            sendMessageToServer();
                        } catch (Exception e) {
                            e.printStackTrace();
                            Log.i("test","error " ,e);
                        }
                    }

                    @Override
                    public void onServiceDisconnected(ComponentName name) {
                        Log.i("test","client onServiceDisconnected name = " +name);
                    }
                }, BIND_AUTO_CREATE);

	void sendMessageToServer() throws RemoteException {
        Message toServer = Message.obtain();
        toServer.replyTo = messengerClientSend;
        toServer.what = 1;
        //toServer.obj = "hello I send from client"; 注意不可以 传递非parcel的对象,这个只能给obj赋值为parcel类型对象否则报错
        Bundle bundle = new Bundle();
        bundle.putString("bundleKey","bundleValue Client");
        toServer.setData(bundle);
        messengerServer.send(toServer);
    }

大家这里注意客户端获取了服务端IBinder对象后,用它来构造客户端的Messenger,
messengerServer = new Messenger(service);
这里注意是和服务端不一样地方
有了服务端Messenger后,那么就可以通过它与服务端进行通信了,通信的内容载体是我们最为属性Message,对他就是和Handler搭配的Message,它就是具体消息体,即你需要发送什么消息,都是把内容转换成Message对象既可以,这里我们案例中传递一个Bundle的对象,这个Bundle对象可以利用键值对方式装载各种各样类型数据。和Intent传递数据Bundle是一样的。注意这里message对象还有一个属性是replyTo ,这个是Messenger类型的,字面意思就是说这个消息发送过去,如果对方需要回复,就可以通过消息中的replyTo 的Messenger对象来进行回复,这里是不是也和我们上节课讲的binder双向通信一样,所以说Messenger这种方式本身就相当于自带了双向通信

3 Messenger本质原理

Messenger其实本质上也是使用aidl进行实现了,只是这个aidl是在Framework层面进行写好了,不需要你写,你也就没有在意,没有看到。这里对他的源码进行分析一下:

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();//这个是handler对象获取IMessenger接口
    }
    
    /**
     * Send a Message to this Messenger's Handler.
     * 
     * @param message The Message to send.  Usually retrieved through
     * {@link Message#obtain() Message.obtain()}.
     * 
     * @throws RemoteException Throws DeadObjectException if the target
     * Handler no longer exists.
     */
    public void send(Message message) throws RemoteException {
        mTarget.send(message);//这其实调用是IMessenger接口的send
    }
    。。。。。省略
    }

代码中注释提到的handler对象获取IMessenger接口,IMessenger 接口到底又是什么呢?
目前我没没有看到有aidl啊。。。

Handler的getIMessenger

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

大家看这里其实就是MessengerImpl ,是继承IMessenger.Stub,大家看到IMessenger.Stub是不是和aidl里面的接口和很熟悉啊。对它其实就是IMessenger.aidl文件生成的


package android.os;

import android.os.Message;

/** @hide */
oneway interface IMessenger {
    void send(in Message msg);
}

这里是不是看到期待已久的aidl了。。还是个oneway类型的哦

以上是关于千里马Android Framework实战开发-binder通信之Messenger介绍的主要内容,如果未能解决你的问题,请参考以下文章

千里马Android Framework实战开发-native程序之间binder通信实战案例分析

千里马Android Framework实战开发-native程序之间binder通信实战案例分析

千里马Android Framework实战开发-跨进程通信专题博客总结

千里马Android Framework实战开发-跨进程通信专题课表介绍

千里马android framework实战开发-binder驱动之oneway导致的transaction failed

千里马android framework实战开发-binder驱动之oneway导致的transaction failed