Android-跨进程通信之Messenger

熟悉Android的开发人员应该都知道,实现不同进程之间通信的方法有5种:
1.通过Bundle/Intent传递数据;
2.通过aidl;
3.通过Messenger;
4.通过ContentProvider;
5.通过socket。
其中1,2,3,4的本质都是通过binder机制来实现的,5是通过网络套接字。

这里主要介绍下第三种方法,通过Messenger实现进程通信。

一. Messenger的使用
通过Messenger来实现进程通信是很简单的,省去了编写aidl代码这部分的工作,全部由系统帮我们封装好了。
步骤:
1、服务端
(1)创建一个服务类TestService,继承自Service。
(2)在TestService中创建一个Handler实例,并重写方法handleMessage:

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        //TODO
        }
}

(3)在TestService中创建Messenger实例,并传入上面创建的Handler实例
Messenger mMessenger = new Messenger(mHandler); //注意:服务端传入的参数是Handler的引用。
并在onBind方法中调用mMessenger的方法getBinder得到IBinder实例返回:

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

这样服务端代码就编写好了,客户端只要通过调用Context.bindService方法即可:
Context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
当客户端调用Messenger的send方法将消息发送到服务端,就会执行mHandler.handleMessage方法。

2、客户端
(1)创建ServiceConnection实例

private Messenger mService  = null;
private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
                mService  = new Messenger(service); //注意:客服端传入的参数是IBinder类型引用
        }
        public void onServiceDisconnected(ComponentName className) {
            mService = null;
        }
};

(2)调用bindService

mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

bind成功后会回调上面实现的mConnection.onServiceConnected方法,这样客户端就得到了远程的IBinder引用,并传入到Messenger,然后客户端可以通过Messenger的send方法,向远程进程发送消息了。

如果说服务器端需要调用客户端的方法,那么同理可以在客户端创建一个Messenger实例,然后通过拿到的服务端IMessenger引用,调用send方法将客户端的Messenger发送给服务端,服务端将持有客户端的类引用了。
下面来实现将客户端的Messenger实例传给服务端。
延续上面的,客户端已经拿到了服务端的Messenger引用,变量名为mService。
然后接下来,
创建Messenger

private Messenger mMessenger = new Messenger(new Handler());

创建Message,并将mMessenger设置给Message,然后通过mService.send方法发送给服务端:

Message msg = Message.obtain(null, 1);
            msg.replyTo = mMessenger;
            try {
                mService.send(msg);
            } catch (RemoteException re) {
                re.printStackTrace();
            }

send之后,服务端的handleMessage方法得到回调后,就可以持有客户端的类引用了。进而实现了服务端和客服端的互相通信。

通过以上代码就实现了使用messenger实现跨进程通信。

二. Messenger跨进程通信的原理
在Handler内部,有一个内部类MessengerImpl,继承自IMessenger.Stub,代码如下:

private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

并且Handler提供方法getIMessenger去获取MessengerImpl 实例。

final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

服务器端创建Messenger时,调用的方法时public Messenger(Handler target),这个方法实现如下:

private final IMessenger mTarget;
public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

就是说创建服务端的Messenger时候,messenger会首先通过Handler的getIMessenger方法得到IMessenger实例。
这样执行后,服务端的Messenger对象就拥有IMessenger的引用,当客户端的程序通过调用bindService方法,执行到服务端的onBind方法后,onBind再调用Messenger的getBinder方法得到IBinder引用,并返回给客户端,getBinder代码如下:

public IBinder getBinder() {
        return mTarget.asBinder();
    }

mTarget即IMessenger实例,这样客户端就拿到了远程的IMessenger引用。

再看客户端这边,bind成功后,回调客户端的onServiceConnected方法,然后该方法中创建Messenger实例,这个创建和服务端很不一样,调用的是另一个构造方法public Messenger(IBinder target),将远程的IMessenger引用传入了,这样就在客户端创建了一个服务端的IMessenger代理类对象,代码如下:

public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

看到这些代码就明白了,客户端的Messenger对象的mTarget的获取和服务端是不一样的,这是在拿到服务端的IBinder引用后,通过调用对应的方法转换成IMessenger类型的引用。

然后再看Messenger的send方法的实现:

public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }

方法中调用mTarget.send,将消息发送给了远程服务端。

系统框架代码写的就是完美,然后在Message类中,定义了一个public Messenger replyTo;然后客户端拿到远程的IMessenger后,就可以创建客户端的Messenger,将Messenger实例引用赋值给replyTo变量,然后通过send方法将携带了客户端的Messenger引用的Message实例发送给服务端。服务端拿到客户端Messenger的引用后就可以方便地调用客户端的方法了。

Messenger实现跨进程通信的本质就是IBinder,所以重点还需要去掌握IBinder的机制。

本文就介绍这么多。

猜你喜欢

转载自blog.csdn.net/songqinging/article/details/88540877
今日推荐