Messenger:轻量级的IPC

QuibblerQuibbler 2020-03-16 约 12 分钟 1800 次阅读

Messenger

1、Messenger

Messenger在不同进程中传递Message对象,在Message中放入我们需要传递的信息,然后通过Messenger将Message传递给对方,就可以轻轻松松实现跨进程数据传递。Messenger是轻量级的IPC(跨进程通信)方式,底层是AIDL实现。

      “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.”

2、服务端

先来看服务端Messenger的编码工作。

2.1、Handler

继承Handler自定义Handler,处理Messenger中的Message消息:

private static class MessengerHandler extends Handler {
         
        public void handleMessage(Message msg) {
            switch (msg.what) {
                ...  
                default:
                    break;
            }
        }
    }

2.2、创建Messenger

将前面定义的Handler作为Messenger构造函数的参数,创建Messenger

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

2.3、onBind()

服务端Service的onBinder()中返回Messenger获得的IBinder:

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

3、客户端

客户端绑定另一个APP或者进程的Service,通过Messenger通信。


3.1、Messenger

客户端定义一个Messenger对象,在绑定到服务端的时候初始化,“引用”到服务端对应的Messenger

private Messenger mMessenger;

3.2、ServiceConnection

服务端Service需要和客户端绑定的方式启动,先定义ServiceConnection:

private ServiceConnection mServiceConnection = new ServiceConnection() {
        
        public void onServiceConnected(ComponentName name, IBinder service) {
            //这里服务端连接上,初始化客户端Messenger
            mMessenger = new Messenger(service);
        }
        
        public void onServiceDisconnected(ComponentName name) {
        }
    };

3.3、绑定服务

通过下面的方式绑定服务端Service,包名是一定要有的。还可以给Intent设置Service一致的Action启动。

Intent intent = new Intent();
    ComponentName componentName = new ComponentName("服务端包名", "服务端Service完整路径");
    intent.setComponent(componentName);
    bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

3.4、给Service发送Message消息

绑定成功Service,也获取到Messenger对象,就可以借助Messenger向服务端发送消息。需要try-catch,因为可能会抛出RemoteException受查异常。

Message message = Message.obtain(null, 1);
    try {
        mMessenger.send(message);
    } catch (RemoteException e) {
        
    }

4、服务端->客户端

前面的是客户端给服务端发送Messenger消息,服务端能不能回应客户端的消息,向客户端发送消息呢?可以。就像是反过来,客户端成了服务端,服务端成了客户端。

4.1、客户端

首先,客户端增加处理服务端发送Message的Messenger和Handler。

客户端定义Handler ,处理服务端的Message:

private static class MessengerHandler extends Handler {
        
        public void handleMessage( Message msg) {
            switch (msg.what) {
                ...
            }
        }
    }

再在客户端定义一个Messenger

private Messenger mClientMessenger = new Messenger(new MessengerHandler());

向服务端发送Message的时候,借助Message中的replyTo字段携带上该客户端Messenger:

Message message = Message.obtain(null, 1);
    message.replyTo = mClientMessenger;
    try {
        mMessenger.send(message);
    } catch (RemoteException e) {
        
    }

4.2、服务端

接下来就是服务端收到客户端的Message,再给客户端发送Message消息,修改服务端中自定义的Handler,从客户端发送的Message中拿到客户端的Messenger,向客户端发送消息:

private static class MessengerHandler extends Handler {
        
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CLIENT:
                    //拿到客户端的Messenger
                    Messenger clientMessenger = msg.replyTo;
                    Message replyMessage = Message.obtain(null, 1);
                    try {
                        //向客户端发送消息
                        clientMessenger.send(replyMessage);
                    } catch (RemoteException e) {
                        Log.e("QUIBBLER", "服务端->客户端失败");
                    }
            }
        }
    }

5、Messenger与AIDL

Messenger底层就是AIDL实现的,是系统封装提供的一个实用进程间通信工具。在《Android开发艺术探索》一书中有详细提到。这里直接引用简书 利用Messenger跨进程通信一文。

5.1、相同点

①都与IPC的调用有关;

②Messenger 是一种轻量级的 IPC方案,底层实现了AIDL,只是进行了封装,开发的时候不用写.aidl文件。

③都支持实时通信;


5.2、不同点

①Messenger一次只能处理一个请求(串行);AIDL一次可以处理多个请求(并行);

       当需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现更加简单,因为  Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。

       对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。

②Messenger不支持RPC,只能通过Message传递消息;AIDL支持RPC;

③Messenger使用简单,轻量级,不需要创建AIDL文件;AIDL使用复杂,需要创建AIDL文件;

相关资料:        

        Android Developers>Docs>Reference

        详解Bundle与“信使”——Messenger

        Android夸进程通信机制三:Messenger与Message
        Android IPC 通信之 Messenger

        Messenger是如何封装AIDL接口的?
        深入了解 Messenger 的实现细节

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w