文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2022-06-06 13:51

关注

文章目录Messenger 是什么Messenger 底层实现Messenger 使用说明案例实现说明新建一个项目创建 ServiceService 代码说明客户端代码说明小结验证结果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();
    }
}

首先,我们创建一个服务端的 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);
    }
}

在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 工作原理 总结

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

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


作者:邹奇


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯