Android夸进程通信机制系列:
Android夸进程通信机制一:多进程简介
Android夸进程通信机制二:Parcel 与 Parcelable
Android夸进程通信机制三:Messenger与Message
Android夸进程通信机制四:使用 Bundle进行进程间通信
Android夸进程通信机制五:使用文件共享进行进程间通信
Android夸进程通信机制六:使用ContentProvider进行进程间通信
Android夸进程通信机制七:使用 Socket进行进程间通信
Android夸进程通信机制八:使用 AIDL进行进程间通信
Android夸进程通信机制九:AIDL深入了解
...


一、前言

经过前面两节,我们知道,进程间传递基本数据和序列化数据,可以通过Messager与Message来搭配实现,那么本文来讲一下Messager与Message。

二、Messenger与Messenge

Messenger 可以翻译为信使,顾名思义,通过它可以在不同进程中传递Message对象.
Message 可以翻译为信封,顾名思义,信封里附带着数据

先看Messenger官方文档的描述:

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.

大概意思是说,首先Messenger要与一个Handler相关联,才允许以message为基础的会话进行跨进程通讯。通过创建一个messenger指向一个handler在同一个进程内,然后就可以在另一个进程处理这个messenger了。

在Message中放入我们需要传递的数据,Messenger就可以轻松地实现在进程间传递数据了。

Messenger

Messenger是一种轻量级的IPC方案,它的底层实现是AIDL,为什么这么说呢,我们大致看一下Messenger这个类的构造方法就明白了。

    /**     * 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();    }    /**     * Create a Messenger from a raw IBinder, which had previously been     * retrieved with {@link #getBinder}.     *      * @param target The IBinder this Messenger should communicate with.     */    public Messenger(IBinder target) {        mTarget = IMessenger.Stub.asInterface(target);    }

从Messenger两个构造方法的实现上我们可以明显看出AIDL的痕迹,不管是IMessenger还是Stub.asInterface,这种使用方法都表明它的底层是AIDL。

我们接着来看Messenger的两个重要方法:

getBinder() : 返回一个IBinder对象,一般在服务端的onBind方法调用这个方法,返回给客户端一个IBinder对象
send(Message msg) : 发送一个message对象到messengerHandler。这里,我们传递的参数是一个Message对象,

Messenge

如果说Messenger充当了信使的角色,那么Message就充当了一个信封的角色。同样地,先看官方文档的描述:

Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.While the constructor of Message is public,the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

从官文的描述可知,该Message对象含有两个Int型的属性和一个object型的属性,然后创建Message的实例,最好调用Message.obtain()方法而不是直接通过构造器。我们来看看主要参数以及重要方法:

  • 属性 public int arg1,public int arg2,public Object obj : 一般这三个属性用于保存数据,其中Object对象用于保存一个对象。
  • 属性 public Messenger replyTo : 这个属性一般用于服务端需要返回消息给客户端的时候用到,下面会说到。
  • 属性 public int what:这个属性用于描述这个message,一般在实例化的时候会传递这个参数。
  • 方法 obtain():提供了多个参数的重载方法,为了获得message实例。
  • setData(Bundle data):设置obj的值,Bundle将在下节单独讲一下。

三、实现举例

Messenger的使用方法很简单,它对AIDL做了封装,使得我们可以更简便地进行进程间通信。同时,由于因为Handler的机制一次处理一个请求,因此在服务端我们不用考虑线程同步的问题。实现一个Messenger有如下几个步骤,分为服务端和客户端。

1. 创建一个Service

首先,我们需要在服务端创建一个Service来处理客户端的连接请求,同时创建一个Handler并通过它来创建一个Messenger对象,然后在Service的onBind中返回这个Messenger对象底层的Binder即可。
代码如下:

public class MessengerService extends Service{    class IncomingHandler extends Handler{        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            switch (msg.what){                case 0:                    Toast.makeText(getApplicationContext(), "hello, trampcr", Toast.LENGTH_SHORT).show();                    break;            }        }    }    Messenger mMessenger = new Messenger(new IncomingHandler());    @Nullable    @Override    public IBinder onBind(Intent intent) {        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();        return mMessenger.getBinder();    }}

2. 声明进程

然后,在AndroidManifest中声明Service并给一个进程名,使该服务成为一个单独的进程。
AndroidManifest配置如下:

3. 创建客户端

户端进程中,首先要绑定服务端的Service,绑定成功后用服务端返回的IBinder对象创建一个Messenger,通过这个Messenger就可以向服务端发送消息了,发消息类型为Message对象。这听起来可能还是有点抽象,不过看了下面的两个例子,读者肯定就都明白了。首先,我们来看一个简单点的例子,在这个例子中服务端无法回应客户端。
首先看服务端的代码,这是服务端的典型代码,可以看到MessengerHandler用来处理客户端发送的消息,并从消息中取出客户端发来的文本信息。而mMessenger是一个Messenger对象,它和MessengerHandler相关联,并在onBind方法中返回它里面的Binder对象,可以看出,这里Messenger的作用是将客户端发送的消息传递给MessengerHandler处理。

public class MessengerActivity extends Activity{    private boolean mBound;    private Messenger mMessenger;    private ServiceConnection mServiceConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            mMessenger = new Messenger(service);            mBound = true;        }        @Override        public void onServiceDisconnected(ComponentName name) {            mMessenger = null;            mBound = false;        }    };    public void sayHello(View v){        if(!mBound){            return;        }        Message msg = Message.obtain(null, 0 , 0, 0);        try {            mMessenger.send(msg);        } catch (RemoteException e) {            e.printStackTrace();        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_messenger);    }    @Override    protected void onStart() {        super.onStart();        Intent intent = new Intent(MessengerActivity.this, MessengerService.class);        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);    }    @Override    protected void onStop() {        super.onStop();        if(mBound){            unbindService(mServiceConnection);            mBound = false;        }    }}

通过以上代码,可以看到Messenger的使用方法:

    1. 服务实现一个Handler,由其接收来自客户端的每个调用的回调。
    1. Handler用于创建Messenger对象(对Handler的引用)。
    1. Messenger创建一个IBinder,服务通过onBind()使其返回客户端。
    1. 客户端使用IBinder将Messenger(引用服务的Handler)实例化,然后使用后者将Message对象发送给服务。
    1. 服务在其Handler中(具体地讲,是在handleMessage()方法中)接收每个Message。

这样,客户端并没有调用服务的“方法”。而客户端传递的“消息”(Message对象)是服务在其Handler中接收的。

四 结语

注意,绑定解绑服务最好在onstart和onStop内,在activity的生命周期里,onStart和onStop是activity在栈顶与否的出口和入口,我们的服务一般是绑定当前activity,顾在这两个位置比较合适。

另外,如果需要服务端能够回应客户端,就和服务端一样,我们还需要创建一个Handler并创建一个新的Messenger,并把这个Messenger对象通过Message的replyTo参数传递给服务端,服务端通过这个replyTo参数就可以回应客户端。

更多相关文章

  1. Android夸进程通信机制六:使用ContentProvider进行进程间通信
  2. Android夸进程通信机制八:使用 AIDL进行进程间通信
  3. Android夸进程通信机制五:使用文件共享进行进程间通信
  4. Android夸进程通信机制一:多进程简介
  5. Android系统启动流程(2) —— 解析Zygote进程启动过程
  6. Android中的Parcel机制 实现Bundle传递对象

随机推荐

  1. 赵雅智_android短信窃听及android短信源
  2. Android 文件的上传
  3. Android webview微信支付白屏
  4. Android shell 创建 模拟器
  5. eclipse项目迁移到android studio(图文最
  6. Android硬件加速
  7. Android系统定制之bootanimation.zip的制
  8. android之socket网络编程
  9. 【Android Studio】Android Studio 安装
  10. Android界面基本属性