Android 进程间通信之Messenger

Android进程间通讯的方式

? 当我们需要执行 IPC(进程间通信)时,一般有两种方式:AIDL和Messenger。关于AIDL的介绍请参看Android进程间通讯之AIDL。我们这里只介绍Messenger

? 使用Messenger要比使用 AIDL 实现它更加简单,因为 Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口。当然采用Messenger的方法实现IPC,实际上是以 AIDL 作为其底层结构。

Messenger 简单介绍

? Messenger会持有一个Handler的引用,我们可以通过使用Messenger向Handler发送消息。而且它是机遇消息(Message)实现的进程间的通信。我们可以在一个进程里通过Handler创建一个Messenger,并发送消息;然后在另一个进程里,通过Messenger接收并处理发送的消息。Messenger的实现是通过Binder进行一些封装;其底层也是使用AIDL实现的。使用Messenger不会出现并发读写问题,因为Messenger是以串行方式工作的,所以如果有大量的请求,不适合使用Messenger。

Messenger进程间通信的简单示例

? 跨进程通信,必然包含客户端和服务端。首先创建一个服务端,接收客户端发送的消息

创建服务端

public class MyService extends Service {

    private static final int MSG_RECEIVE_CLIENT = 0x001;
    //用来接收客户端发送的消息的Messenger
    private Messenger mMessenger;

    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //通过Handler创建Messenger,用来接收客户端发送的消息
        mMessenger = new Messenger(new ReceiveClientMessageHandler());
    }

    @Override
    public IBinder onBind(Intent intent) {
        //当我们绑定Service时,获取一个IBinder,用来跟跟它相关的Handler通信
        return mMessenger.getBinder();
    }

    private  class ReceiveClientMessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case MSG_RECEIVE_CLIENT:
                    //接收客户端发来的信息
                    //Messenger发送的内容必须是经过序列化过的对像,如果要传递对象需要实现Parcelable接口
                    String clientMsg = msg.getData().getString("key");
                    Toast.makeText(getApplicationContext(), clientMsg, Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }
}

然后在AndroidMenifest.xml里声明一下Service。

<service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.liteng.service.messenger"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
</service>

这样我们的服务端就完成了,接下来我们来完成客户端.

创建客户端

为了看起来直观一些,我们添加一个按钮。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.liteng.client.MainActivity">

    <Button
        android:onClick="sendMsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind Service"/>
</RelativeLayout>

然后我们在去Activity里去绑定Service;

public class MainActivity extends AppCompatActivity {
    public String action = "com.liteng.service.messenger";
    private static final int MSG_SEND = 0x001;
    private Messenger mMessenger;

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

        Intent intent = new Intent(action);
        //设置服务端的包名
        intent.setPackage("com.liteng.service");
        //绑定Service
        bindService(intent,mConnection,BIND_AUTO_CREATE);
    }

    public void sendMsg(View view) throws RemoteException {
        //创建Message对象
        Message msg = new Message();
        msg.what = MSG_SEND;
        Bundle bundle  = new Bundle();
        bundle.putString("key","i am from client");
        //Messenger发送的内容必须是经过序列化过的对像,如果要传递对象需要实现Parcelable接口
        msg.setData(bundle);
        mMessenger.send(msg);
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //当跟Service的连接建立时,我们通过IBinder创建一个Messenger来跟服务端进行通信
            mMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mMessenger = null;
        }
    };
}

我们在客户端向服务端发送一句话“i am from client”。接下来我们去运行一下程序,去看看服务端是否会弹出Toast显示这句话。

我们可以看到成功的弹出了我们想要的结果。

上面我们完成了客户端请求,服务端获取客户端的消息。那么服务端接收到消息之后,处理完消息之后如何再发消息给客户端的呢?我们接着说。

服务端发消息给客户端

? 首先,我们是在Handler里获取到的客户端发来的消息,那么我们可以根据Message对象去获取发送消息的Messenger,然后将消息发送给客户端。

? Message提供了一个变量replyTo,用来存储发送和接收消息的Messenger;具体如何使用呢?我们只需要获取到Messenger之后,重复发送消的步骤就OK。关键我们去看看客户端是如何接收服务端回应消息。

? 既然我们需要在客户端里接收服务端发送的消息,那么我们就必须在客户端实现一个接收消息的Messenger,并且提供一个接收消息的Handler,如下:

 private Messenger mClientMessenger = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msgFromService) {
            super.handleMessage(msgFromService);
            switch (msgFromService.what){
                case MSG_RECEIVE:
                    //获取服务端发送过来的消息
                   String fromService=msgFromService.getData().getString("fromService");
                    //将获取到的消息显示到Button上
                 ((Button)findViewById(R.id.btnSendMsg)).setText(fromService);
                    break;
            }
        }
    });

然后我们在发送消息的地方设置发送/接收消息的Messenger:

//设置我们在客户端接收消息的Messenger.
msg.replyTo = mClientMessenger;

我们设置完毕客户端之后,我们去服务端获取我们接收消息的Messenger:

//当服务端接收到客户端发送的消息之后,我们回应给客户端
//获取到发送给服务端消息的Messenger
Messenger clientMessenger = msgFromClient.replyTo;
Message message = new Message();
message.what = MSG_SEND_CLIENT;
Bundle bundle = new Bundle();
bundle.putString("fromService", "i am from service");
message.setData(bundle);

这样我们就可以从服务端往客户端发送消息了;完整代码如下:

客户端

我们只需要一个Activity就可以了:

public class MainActivity extends AppCompatActivity {
    public String action = "com.liteng.service.messenger";
    private static final int MSG_SEND = 0x001;
    private static final int MSG_RECEIVE = 0x002;

    private Messenger mServiceMessenger;

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

        Intent intent = new Intent(action);
        //设置服务端的包名
        intent.setPackage("com.liteng.service");
        //绑定Service
        bindService(intent,mConnection,BIND_AUTO_CREATE);

    }

    public void sendMsg(View view) throws RemoteException {
        //创建Message对象
        Message msg = Message.obtain();
        msg.what = MSG_SEND;
        Bundle bundle  = new Bundle();
        bundle.putString("key","i am from client");
        //Messenger发送的内容必须是经过序列化过的对像,如果要传递对象需要实现Parcelable接口
        msg.setData(bundle);
        //设置我们在客户端接收消息的Messenger.
        msg.replyTo = mClientMessenger;

        mServiceMessenger.send(msg);
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //当跟Service的连接建立时,我们通过IBinder创建一个Messenger来跟服务端进行通信
            mServiceMessenger = new Messenger(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mServiceMessenger = null;
        }
    };

    private Messenger mClientMessenger = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msgFromService) {
            super.handleMessage(msgFromService);
            switch (msgFromService.what){
                case MSG_RECEIVE:
                    //获取服务端发送过来的消息
                    String fromService = msgFromService.getData().getString("fromService");
                    //将获取到的消息显示到Button上
                    ((Button)findViewById(R.id.btnSendMsg)).setText(fromService);
                    break;
            }
        }
    });
}

服务端:

我们的操作几乎都在Service里面:

public class MyService extends Service {

    private static final int MSG_RECEIVE_CLIENT = 0x001;
    private static final int MSG_SEND_CLIENT = 0x002;
    //用来接收客户端发送的消息的Messenger
    private Messenger mMessenger;

    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //通过Handler创建Messenger,用来接收客户端发送的消息
        mMessenger = new Messenger(new ReceiveClientMessageHandler());
    }

    @Override
    public IBinder onBind(Intent intent) {
        //当我们绑定Service时,获取一个IBinder,用来跟跟它相关的Handler通信
        return mMessenger.getBinder();
    }

    private class ReceiveClientMessageHandler extends Handler {
        @Override
        public void handleMessage(Message msgFromClient) {
            super.handleMessage(msgFromClient);
            switch (msgFromClient.what) {
                case MSG_RECEIVE_CLIENT:
                    //接收客户端发来的信息
                    //Messenger发送的内容必须是经过序列化过的对像,如果要传递对象需要实现Parcelable接口,不能直接传递String
                    String clientMsg = msgFromClient.getData().getString("key");
                    Toast.makeText(getApplicationContext(), clientMsg, Toast.LENGTH_SHORT).show();

//                  当服务端接收到客户端发送的消息之后,我们回应给客户端
//                  获取到发送给服务端消息的Messenger
                    Messenger clientMessenger = msgFromClient.replyTo;
                    Message message = new Message();
                    message.what = MSG_SEND_CLIENT;
                    Bundle bundle = new Bundle();
                    bundle.putString("fromService", "i am from service");
                    message.setData(bundle);
                    try {
                        clientMessenger.send(message);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    }
}

最后我们看一下效果:

当我们点击按钮时,先向服务端发送消息,弹出吐司“i am from client”,然后从服务端发送消息给客户端,更改按钮的文字”I am from Service”。

这样,客户端服务端互发消息就实现了,注意事项有一下几点:

  1. Messenger发送的内容必须是经过序列化过的对像,如果要传递对象需要实现Parcelable接口,否则会有以下异常:
  2. 不要执行多线程处理,如果您的服务必须执行多线程处理,则应使用 AIDL 来定义接口
  3. 如果需要客户端往服务端发送消息,一定要调用replyTo设置发送和接收消息的Messenger.

先写这些吧,其它想起来再写。有什么问题,希望看到的同学给予提示,拜谢!

时间: 2024-12-13 08:00:05

Android 进程间通信之Messenger的相关文章

浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6621566 上一篇文章Android进程间通信(IPC)机制Binder简要介绍和学习计划简要介绍了Android系统进程间通信机制Binder的总体架构,它由Client.Server.Service Manager和驱动程序Binder四个组件构成.本文着重介绍组件Service Manager,它是整个Binder机制的守护进程,用来管理

android进程间通信:使用AIDL

欢迎阅读本文,你能关注本文,你知道你需要进程间通信.需要AIDL(以及Binder),那么可以默认你对这些概念已经有了一些了解,你(大致)知道它们是什么,它们有什么用,所以为了节约大家的眼力和时间,在此我不复制粘贴网上泛滥的博客或者翻译冗长的android文档. 关于AIDL的介绍在文档:docs/guide/developing/tools/aidl.html 关于IBinder的介绍在文档:docs/reference/android/os/IBinder.html 以及Binder:doc

Android进程间通信之内部类作为事件监听器

在Android中,使用内部类可以在当前类里面发用改监听器类,因为监听器类是外部类的内部类,所以可以自由访问外部类的所有界面组件.以下是一个调用系统内部类实现短信发送的一个例子: SMS类: package com.example.msmlistener; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.telephony.Sm

饿了么开源项目Hermes:新颖巧妙易用的Android进程间通信IPC框架

版权所有.所有权利保留. 欢迎转载,转载时请注明出处: http://blog.csdn.net/xiaofei_it/article/details/51464518 Android进程间通信IPC是比较高级的话题,很多Android程序员碰到IPC就觉得头疼,尤其是AIDL这类东西. 公司最近在研究DroidPlugin插件开发,DroidPlugin把每个子app都变成一个进程.这样的话子app和主app如果需要共享数据,就需要IPC.所以我开发了Hermes框架,让IPC变得非常简单优雅

初识Android进程间通信之----Binder机制

[转载请注明出处:http://blog.csdn.net/feiduclear_up/article/details/51405967 CSDN废墟的树] 前言 前面两篇博客分别介绍了Android进程间通信之AIDL的使用,以及使用AIDL传递复杂对象以及Bitmap对象.所谓AIDL:Android Interface Definition Language,是一种Android接口定义语言,用于编写Android进程间通信代码.也就是说AIDL只是一个实现进程间通信的一个工具,真正实现A

Android进程间通信与数据共享(ppt)

Android进程间通信与数据共享(ppt)

Android进程间通信之----Aidl传递对象

转载请注明出处 CSDN废墟的树 前言 有关Android进程间通信之Aidl编程的基本使用步骤已经在上一篇博客中有讲解,Android studio 下的aidl编程实现Android的夸进程间通信.上一篇博客中只是演示了怎么利用Aidl实现跨进程间传递Java基本类型,以及Aidl传递Bitamap对象.可能在一些场景下你需要跨进程传递一个对象,那么Aidl是否能传递一个对象呢?答案是肯定的,网上也有很多相关的资料,之所以写这篇博客:一是当作自己学习笔记咯,二是把自己遇到的问题分享出来. A

AIDL实现Android进程间通信实例

实现Android进程间通信实例有好几种方法: 1,AIDL 2,Broadcast 3,Intent 4,Content Provider 记录一下AIDL实现Android进程间通信的方式: Android的AIDL进程间通信实现步骤: 一:创建AIDL服务端:aidl文件,自动生成的接口java文件,服务service xxxInterface.aidl  (远程服务的接口定义) package com.example.aidltest; interface IMyAidlInterfac

Android应用进程间通信之Messenger信使使用及源码浅析

1 背景 这个知识点是个low货,刚开始其实想在之前一篇文章<Android异步消息处理机制详解及源码分析>一文中作为一个知识点分析的,但是想了又想又觉得该放在后面进程间通信分析时再分析.然并卵,还是单独拿出来写一篇分析一下吧. 提到Message和Handler其实大家都很熟悉,但是说到Messenger估计有些人还是不太常用的,更有甚者都能把Messenger拼写错误为Messager,以为是Message加了个r,当然,网络上对于Messenger的文章现在也很多了,但是个人分析总结总归