当前位置:   article > 正文

Android中使用 Messenger 实现进程间通信小案例与分析说明_android messenger 例子

android messenger 例子

Messenger 是什么

Messenger 可以翻译为信使,顾名思义,通过它可以实现在不同进程中传递 Message 对象,在 Message 中可以携带我们需要传递的数据,借此就可以实现数据在不同进程间的通信。


Messenger 底层实现

Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL ,这块同学们可以通过看 Messenger 这个类的源码中的构造方法得知。


Messenger 使用说明

Messenger的使用会相对简单,它对 AIDL 做了封装,使得我们可以更便捷的进行进程间通信。
同时,由于它一次处理一个请求,因此服务端我们不用考虑线程同步的问题,这是因为服务端此时不存在并发执行的情形。


案例实现

说明

案例只用到了一个应用,首先是一个 Activity,把Activity 里的代码当作客户端的代码,后面统称客户端;服务端我们用一个 Service 组件(后面统称服务端)来实现,然后通过客户端和 Service 绑定来启动服务端,进而模拟实现客户端和服务端的通信。

同学们这时候有疑问了?

你这不是在同一个进程吗?不急往下看。

这里我们创建好 Service 后,会另外在清单配置文件中给 Service 组件添加一个 process 属性,用来使 Service 组件运行在另一个进程。这样就可以在一个应用中模拟两个进程的运行了,也方便demo的实现。

至于组件的 process 属性,同学们自行查阅资料学习,这里不细说了。

清单配置文件如下图示:

在这里插入图片描述


新建一个项目

新建操作,我就不给出了,同学们自己完成。


创建 Service

项目新建完成后,带有一个 Activity ,我们就当作客户端用,然后再创建一个 Service,命名为 MessengerService.java ,如下图示:

在这里插入图片描述
在这里插入图片描述

这里只用到了 3 个类,其中 MyConstant.java 的代码如下图示:

在这里插入图片描述
别忘记在清单配置文件中给 MessengerService 这个服务配置 process 属性,如下图示:

在这里插入图片描述

到这里我们就拥有了客户端和服务端了。


Service 代码说明

首先给出代码,如下:

package com.example.messengerdemo.service;

import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import com.example.messengerdemo.constant.MyConstant;

public class MessengerService extends Service {

    private static final String TAG = "MessengerService";

    public MessengerService() {
    }

    private static class MessengerHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MyConstant.MSG_FROM_CLIENT:

                    // 接收客户端发来的消息并打印
                    Log.e(TAG, "receive msg from client:" + msg.getData().getString(MyConstant.MSG));

                    // 获取客户端的 Messenger 对象,用来回复客户端消息
                    Messenger clientMessenger = msg.replyTo;
                    Message replyMessage = Message.obtain(null, MyConstant.MSG_FROM_SERVER);
                    Bundle bundle = new Bundle();
                    bundle.putString(MyConstant.REPLY, "消息已经收到,稍后回复你。");
                    replyMessage.setData(bundle);
                    try {
                        clientMessenger.send(replyMessage);// 回复客户端:服务端我已经接收消息
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }

                    break;
            }
        }
    }

    // 创建 Messenger 对象,作用是将客户端的发送的消息传递给 MessengerHandler 处理
    private final Messenger messenger = new Messenger(new MessengerHandler());

    @Override
    public IBinder onBind(Intent intent) {
        // 服务端返回 Messenger 对象底层的 binder
        return messenger.getBinder();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

首先,我们创建一个服务端的 Handler,这里命名为 MessengerHandler 继承 Handler,然后重写 handleMessage() 方法来处理客户端发来的消息,如下图示:

在这里插入图片描述

那么消息怎么传递给 MessengerHandler 呢,我们就要用到 Messenger 对象了,所以需要创建一个 Messenger 对象,如下图示:

在这里插入图片描述

然后你在客户端需要获取到服务端的 Messenger 对象,这样才能给服务端发消息,所以还需要在 onBind() 方法中返回服务端 Messenger 对象底层的 binder,如下图示:

在这里插入图片描述

所以我们到这里就可以知道,创建一个 Messenger 对象,他的构造方法里的参数既可以是 Handler 类型参数,也可以是 IBinder 类型的参数,这里通过看类的源码的构造方法可以看出,如下图示:

在这里插入图片描述


客户端代码说明

首先给出 activity 中的代码,如下:

package com.example.messengerdemo.activity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

import com.example.messengerdemo.R;
import com.example.messengerdemo.constant.MyConstant;
import com.example.messengerdemo.service.MessengerService;

public class MainActivity extends AppCompatActivity{

    // 服务端通过获取客户端的 Messenger 对象 回复消息给客户端 所以客户端也需要声明这么一个 Messenger 对象
    private Messenger getReplyMessenger = new Messenger(new MessengerHandle());
    private static class MessengerHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MyConstant.MSG_FROM_SERVER:

                    Log.e("TAG", "receive msg from server:" +
                            msg.getData().getString(MyConstant.REPLY));

                    break;
            }
        }
    }

    private Messenger messenger = null;// 声明 Messenger 对象,初始化获取服务端的Messenger对象用

    // 创建 ServiceConnection 对象
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            messenger = new Messenger(iBinder);// 通过服务端返回的 binder 创建 Messenger 对象

            // 创建Message对象并设置携带的数据
            Message message = Message.obtain(null, MyConstant.MSG_FROM_CLIENT);
            Bundle bundle = new Bundle();
            bundle.putString(MyConstant.MSG, "imxiaoqi, enjoy coding.");
            message.setData(bundle);

            message.replyTo = getReplyMessenger;// 保证服务端处理消息的时候,能获取到客户端的Messenger对象
            try {
                messenger.send(message);// 通过服务端的Messenger对象发送消息给服务端
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }

        // 在正常情况下该方法是不被调用的,它的调用时机是当Service服务被异外销毁时,权例如内存的资源不足时
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.e("TAG", "MainActivity onServiceDisconnected callback");
        }
    };

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

        // 绑定服务,开启了新的服务进程(后面统一称服务端)
        Intent intent = new Intent(MainActivity.this, MessengerService.class);
        bindService(intent, connection, Context.BIND_AUTO_CREATE);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 活动销毁,记得解绑服务
        unbindService(connection);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

在onCreate() 方法中,我们绑定服务开启服务端进程,如下图示:

在这里插入图片描述

onDestory() 方法就是正常的解绑服务的操作,没什么好说的;

这里同学们应该有注意到,绑定服务的代码中有一个 connection 参数,这个参数其实一个 ServiceConnection 对象,所以我们还需要创建一个 ServiceConnection 对象,这个对象的作用是用来获取服务端的 Messenger 对象并给服务端发送消息,这些操作是在 onServiceConnected() 方法中实现,正常通过绑定方式启动服务并建立连接后,会回调该方法,如下图示:

在这里插入图片描述

上图中创建 Message 对象并设置携带的数据以及通过服务端的 Messenger 对象发送消息给服务端大家都比较好理解。

但是有一行代码可能同学们会存在疑惑,就是
message.replyTo = getReplyMessenger;// 保证服务端处理消息的时候,能获取到客户端的Messenger对象
。其实这行代码的作用是:为了在发给服务端的消息中携带客户端的 Messenger 对象,这样服务端就可以通过 message(客户端发来的) 获取客户端的 Messenger 对象,也就能使用这个对象回复消息给客户端说我已经接收到你的消息了。

所以,如果服务端需要回复消息给客户端,那么我们的客户端肯定也是需要有一个 Messenger 对象和 一个 Handler 对象的,只有存在这两个对象才可以接收到服务端的消息并作处理,如下图示:

在这里插入图片描述

服务端获取客户端的 Messenger 对象代码,如下图示:

在这里插入图片描述


小结

到这里代码就全部完成,我们来梳理一下上面都做了什么操作,可以实现什么功能?

我们在一个应用中模拟了客户端和服务端,并运行在不同进程;然后客户端可以发消息给服务端,服务端接收到消息并处理消息,log打印客户端消息;同时服务端收到消息后,再回应客户端说我已经接收到你发给我的消息了,这时候我们在客户端接收到消息并处理后,也用log打印服务端回复的消息。


验证结果

我这里连接到了自己的手机,运行应用测试,我们来看一下。

  • usb连接手机,点击按钮运行应用:
    在这里插入图片描述

  • 运行成功后打开 logcat 窗口查看日志:

在这里插入图片描述
上图说明服务端已经接收到客户端的消息并做了打印

  • 两个组件运行在两个不同进程,如下:

在这里插入图片描述
com.example.messengerdemo这个对应 activity 的进程,com.example.messengerdemo:remote这个对应 service 组件的进程

  • 切换到 activity 进程打印窗口查看,如下:

在这里插入图片描述
上面说明客户端已经接收到了服务端回复的消息

  • 到这里就完成了使用 Messenger 实现进程间通信的小案例,希望对同学们有所帮助。

Messenger 工作原理

Client
Client-Message
Service
Service-Handler
Client-Handler
Service-Message
Messenger
replyTo-Messenger

总结

这里再次强调,之所以选择在同一个应用内进行进程间通信,是因为操作起来方便,方便,方便。但是效果和在两个应用间进行进程间通信时一样的。

还有一点大家需要知道:同一个应用的不同组件,如果它们运行在不同进程中,那么和它们分别属于两个应用没有本质区别。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/122595
推荐阅读
相关标签
  

闽ICP备14008679号