Android IPC之Messenger

/ 0评 / 1

前言

上一篇中介绍了AIDL的进阶部分,本篇则介绍下基于AIDL的Messenger的用法。Messenger翻译为"信使"。可以用来进行跨进程通信而不用我们手动的编写AIDL文件,提高了开发效率。

Messenger使用流程:客户端进程中,首先要绑定服务端的Service,绑定成功后使用服务端返回的IBinder对象即可创建一个Messenger,通过这个Messenger客户端就可以向服务端发送消息了,发送消息的类型为Message对象,如果需要服务端能够回应客户端,就和服务端一样,客户端需要创建一个Messenger对象以及一个Handler对象,并将客户端创建的Messenger对象对通过Message的replyTo参数发送给服务端,那么服务端就可以通过replyTo携带的Messenger对象回应客户端了。

举个栗子

首先定义服务端,可以看到,首先定义了一个Handler对象用来处理消息,然后使用此Handler对象初始化Messenger对象,最后在onBind中将Messenger对象转换为Binder对象返回,这样一个简单的服务端就完成了。

//RemoteService.java
public class RemoteService extends Service {

    private static final class RemoteHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Log.i("IPC", "msg.what = " + msg.what);
            if (msg.what == RemoteConstants.MESSAGE_FROM_CLIENT) {
                Bundle data = msg.getData();
                String string = data.getString("msg");
                Log.i("IPC", string);
            }
        }
    }

    // 处理客户端消息的Handler
    private RemoteHandler mHandler = new RemoteHandler();

    // 传递消息的Messenger
    private Messenger mMessenger = new Messenger(mHandler);

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

然后看看客户端的实现,首先bind远程服务,然后在onServiceConnected方法中通过第二个参数初始化Messenger,这样就将客户端与服务端连接起来了,然后通过发送一个Message给服务端,就完成了一次客户端到服务端的通信。

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // 创建Messenger对象
    private Messenger mMessenger;

    private ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("IPC", "remote service died");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("IPC", "onServiceConnected");
            // 使用IBinder对象初始化Messenger对象
            mMessenger = new Messenger(service);
            // 获取一个消息对象
            Message message = Message.obtain();
            message.what = RemoteConstants.MESSAGE_FROM_CLIENT;
            // 设置需要传递的数据
            Bundle data = new Bundle();
            data.putString("msg", "msg from client");
            message.setData(data);
            try {
                mMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };

    public void onBind(View v) {
        Intent intent = new Intent(this, RemoteService.class);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        Log.i("IPC", "bind Remote Service");
    }

    @Override
    protected void onDestroy() {
        unbindService(mServiceConnection);
        Log.i("IPC", "unbindService");
        super.onDestroy();
    }
}

双向通信的栗子

在本文最初部分已经介绍了,要想服务端能发送消息给客户端,需要客户端也有一个Messenger对象以及一个Handler分别用来让服务端返回数据以及处理服务端返回回来的数据,并且这个Messenger对象是通过Message的replyTo字段发送给服务端的,所以修改以后的客户端代码如下。

public class MainActivity extends Activity {
	
	//处理服务端返回的消息
    private static final class ClientHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            if (msg.what == RemoteConstants.MESSAGE_FROM_REMOTE) {
                Bundle data = msg.getData();
                String string = data.getString("msg");
                Log.i("IPC", string);
            }
        }
    }

    // 处理服务端返回的消息
    private ClientHandler mClientHandler = new ClientHandler();

    // 获取远程服务的消息的Messenger
    private Messenger mClientMessenger = new Messenger(mClientHandler);

    // 创建Messenger对象
    private Messenger mMessenger;

    private ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i("IPC", "remote service died");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i("IPC", "onServiceConnected");
            // 使用IBinder对象初始化Messenger对象
            mMessenger = new Messenger(service);
            // 获取一个消息对象
            Message message = Message.obtain();
            message.what = RemoteConstants.MESSAGE_FROM_CLIENT;
            // 设置需要传递的数据
            Bundle data = new Bundle();
            data.putString("msg", "msg from client");
            message.setData(data);
			//将自己的Messenger对象发送给服务端
            message.replyTo = mClientMessenger;
            try {
                mMessenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    };
}

然后服务端在收到客户端的消息以后,通过Message对象的replyTo字段即可获取到客户端传递过来的Messenger对象。并通过这个Messenger对象发送数据给客户端。修改后的代码如下。

public class RemoteService extends Service {

    private static final class RemoteHandler extends Handler {

        @Override
        public void handleMessage(Message msg) {
            Log.i("IPC", "msg.what = " + msg.what);
            if (msg.what == RemoteConstants.MESSAGE_FROM_CLIENT) {
                Bundle data = msg.getData();
                String string = data.getString("msg");
                Log.i("IPC", string);
                // 开始回复客户端
                Messenger replyTo = msg.replyTo;
                if (replyTo != null) {
                    Message obtain = Message.obtain();
                    obtain.what = RemoteConstants.MESSAGE_FROM_REMOTE;
                    Bundle bundle = new Bundle();
                    bundle.putString("msg", "msg from Service");
                    obtain.setData(bundle);
                    try {
                        replyTo.send(obtain);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // 处理客户端消息的Handler
    private RemoteHandler mHandler = new RemoteHandler();

    // 传递消息的Messenger
    private Messenger mMessenger = new Messenger(mHandler);

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

权限认证

上一篇中,对于AIDL的权限认证介绍了两种方法,由于Messenger是基于AIDL的,所以其中的一种方法对于Messenger也是适用的,如下。

//AndroidManifest.xml
//定义需要的权限
<permission android:name="org.remote.IPC" />
//声明此权限
<uses-permission android:name="org.remote.IPC" />

然后在远程Service中进行权限认证,如下

public class RemoteService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        int check = checkCallingOrSelfPermission("org.remote.IPC");
        if (check == PackageManager.PERMISSION_DENIED) {
            Log.i("IPC", "bind error");
            return null;
        }
        return mMessenger.getBinder();
    }
}

Demo地址:https://github.com/CB2Git/IPCPracticeDemo/tree/master/MessengerDemo

发表评论

您的电子邮箱地址不会被公开。