(原创)Flutter与Native通信的方式:EventChannel和BasicMessageChannel

前言

上一篇博客主要介绍了MethodChannel的使用方式
Flutter与Native通信的方式:MethodChannel
这篇博客接着讲另外两种通信方式
EventChannel和BasicMessageChannel

EventChannel用于从native向flutter发送通知事件,例如flutter通过其监听Android的重力感应变化等。与MethodChannel不同,EventChannel是native到flutter的单向调用,调用是多播(一对多)的,可以类比成Android的Brodcast。

BasicMessageChannel用于在flutter和native互相发送消息,一方给另一方发送消息,收到消息之后给出回复。它和MethodChannel的区别重在一个消息的回复

EventChannel

Android端调用Flutter端

首先是Flutter端代码,创建一个EventChannel并约定好字段:

static const EventChannel _channel = EventChannel('tofluttereventchannel');

然后写好被调用的方法:

  void _enableEventReceiver() {
    //延时3s,先让 Android 端的 EventChannel 进行初始化 , 然后在 Flutter 端注册 EventChannel 监听
    //这样才能确保连接成功
    Future.delayed(const Duration(milliseconds: 5000), () {
      _streamSubscription =
          _channel.receiveBroadcastStream().listen((dynamic event) {
        print('收到消息 event: $event');
        setState(() {
          mMessage = event;
        });
      }, onError: (dynamic error) {
        print('出现错误 error: ${error.message}');
        setState(() {
          errmMessage = error.message;
        });
      });
    });
  }

_enableEventReceiver方法可以放到Widget的initState()中初始化
在dispose()中调用以下取消监听的方法:

  void _disableEventReceiver() {
    if (_streamSubscription != null) {
      print("flutter断开连接");
      //断开连接,这里也会触发android端的onCancel方法
      _streamSubscription?.cancel();
      _streamSubscription = null;
    }
  }

然后来到Android端,定义两个对象
一个是EventChannel,一个是EventSink:

  private lateinit var channel: EventChannel
  var eventSink: EventChannel.EventSink? = null

继续在configureFlutterEngine方法中做处理:

    channel = EventChannel(flutterEngine.dartExecutor, "tofluttereventchannel")
    channel.setStreamHandler(
      object : EventChannel.StreamHandler {
        override fun onListen(arguments: Any?, events: EventChannel.EventSink) {
          Log.d("MyFlutterActivity", "已建立连接")
          eventSink = events
        }

        override fun onCancel(arguments: Any?) {
          Log.d("MyFlutterActivity", "已断开连接")
        }
      })

可以看到,其实就是在建立连接后对EventSink对象进行赋值
当eventSink 赋值后,就可以拿他进行消息的发送了
比如:

  override fun onResume() {
    super.onResume()
    //这里延时执行是为了模拟eventSink初始化后,我们在业务里面进行消息的发送
    Handler().postDelayed({
      eventSink?.success("这是来自安卓的消息")
      //执行了endOfStream后,再发送消息就无效了,所以这行代码要放到endOfStream上面执行
      eventSink?.error("error code", "这是来自安卓的错误消息", "error details")
      //结束通信,这时候onCancel会被调用
      eventSink?.endOfStream()
    }, 6000)
  }

这样EventChannel的使用就介绍完了

注意

在实际运行时,可能会发现不起作用
归根结底是注册和调用顺序问题
所以最好在Flutter先延迟一下注册监听
让 Android 端的 EventChannel 先建立连接,
然后在 Flutter 端注册 EventChannel 监听
这样才能确保连接成功
所以用 Future.delayed 进行延时操作
具体可以参考这篇博客:
Flutter 混合开发报错

MessageChannel

MessageChannel重在回调后的消息回复
相对与其他Channel类型的创建,MessageChannel的创建除了channel名以外,还需要指定编码方式。
因为发送的消息会以二进制的形式进行处理,所以要针对不同类型的数进行二进制编码
主要方式有:
在这里插入图片描述
下面看具体使用

Flutter端

Flutter端,首先定义BasicMessageChannel

  static const messageChannel = BasicMessageChannel('tofluttemessagechannel', StringCodec());

发送消息这样写:

  ///发送MessageChannel消息,延时一下,确保安卓端先注册了监听才能收到
  void _sendMessage()  {
    Future.delayed(const Duration(milliseconds: 6000), () async {
      final String? result = await messageChannel.send('来自flutter主动发送的消息');
      print("收到安卓端的返回值:${result}");
    });
  }

可以看到发送后会拿到返回值result

注册回调,也就是接受消息这样写:

    //注册MessageChannel消息监听
    messageChannel.setMessageHandler((message) async {
      print('收到安卓端的MessageChannel消息 = $message');
      setState(() {
        forNativeMsg = message ?? "";
      });
      return '来自flutter返回的消息';
    });
    //发送MessageChannel消息

可以看到接收到后也会给到Android端一个返回值
利用BasicMessageChannel,我们就很快的完成了消息的发送和接收
并且每一个操作都可以接受或者传送返回值

Android端

Android端其实和Flutter端几乎一样
首先是定义BasicMessageChannel

    //先注册MessageChannel
    val messageChannel = BasicMessageChannel(
      flutterEngine.dartExecutor,
      "tofluttemessagechannel",
      StringCodec.INSTANCE)

发送消息:

    //发送消息
    Handler().postDelayed({
      messageChannel.send("来自安卓端主动发送的消息") { result ->
        Log.d("MyFlutterActivity", "收到flutter端的返回值:$result")
      }
    }, 500)

注册回调,也就是接受消息

    //先注册监听
    messageChannel.setMessageHandler { message, reply ->
      Log.d("MyFlutterActivity", "收到flutter端的MessageChannel消息:"+message)
      reply.reply("来自安卓端返回的消息")
    }

注意

这里其实也要注意一个顺序问题
总结起来就是:先注册,后发送
先让被回调的那一端注册监听完成后
再去跨端调用,也就是发送消息

总结

最后来总结一下三种方式的区别:

通信方式双端通信指定编码注册顺序使用场景
MethodChannel支持不需要延时注册方法调用
EventChannelNative单向调用Flutter先建立连接再监听广播通知
BasicMessageChannel支持先注册,再监听用于传递字符串和半结构化的消息

源码

源码地址:
EventChannel和BasicMessageChannel

相关资料

这是一份全面 & 详细的Android Native与Flutter的通信方式 学习指南

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/51984.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)模拟实现正反向迭代器【容器适配器模式】

深入篇【C】手搓模拟实现list类(详细剖析底层实现原理)&& 模拟实现正反向迭代器【容器适配器模式】 Ⅰ.迭代器实现1.一个模板参数2.两个模板参数3.三个模板参数 Ⅱ.反向迭代器实现1.容器适配器模式 Ⅲ.list模拟实现1.定义结点2.封装结点3.构造/拷贝4.迭代器…

线性代数的学习和整理2:用EXCEL进行矩阵计算

目录 0 写在前面的话 网上推荐的线性代数的课程 1 线性代数和矩阵的各种概念 1.1 各种逻辑图 2 关于线性代数入门的各种灵魂发问 2.1 什么是线性,什么是线性相关 ? 为什么叫线性变换? 为什么叫线性代数? 2.2 线性代数是人造…

janus-Gateway的服务端部署

janus-Gateway 需求是前后端的webRTC推拉流,但是后端用的是c,于是使用了这个库做视频流的推送和拉取,记录踩坑过程。 如果你也需要自己部署janus的服务端并在前端拉流测试,希望对你有所帮助。 由于janus的服务器搭建需要linux环境…

无涯教程-jQuery - jQuery.get( url, data, callback, type )方法函数

jQuery.get(url,[data],[callback],[type])方法使用GET HTTP请求从服务器加载数据。 该方法返回XMLHttpRequest对象。 jQuery.get( url, [data], [callback], [type] ) - 语法 $.get( url, [data], [callback], [type] ) 这是此方法使用的…

RWEQ模型——土壤风蚀模拟

详情点击链接:基于“RWEQ”集成技术在土壤风蚀模拟与风蚀模数估算、变化归因分析中的实践应用及SCI论文撰写 前沿 土壤风蚀是一个全球性的环境问题。中国是世界上受土壤风蚀危害最严重的国家之一,土壤风蚀是中国干旱、半干旱及部分湿润地区土地荒漠化的…

QObject::connect: No such signal me::sendMsg(QString s) in ...

QObject::connect: No such signal me::sendMsg(QString s) in ... 解决方案 在使用qt4的connect中,爆的bug: 导致 teacher 的槽函数 receiveMsg(QString s) 一直没有被调用。。。。 解决方案 去掉参数名, 保留类型…

我的第一个flutter项目(Android Webview)

前言:flutter开发环境搭建Flutter的开发环境搭建-图解_☆七年的博客-CSDN博客 第一个flutter简单项目,内容是一个主界面,其中: 1.内容点击数字自增 2.跳转一个空页, 3.跳转一个WebView界面 其中涉及添加主键&#xf…

【C++ 进阶】继承

一.继承的定义格式 基类又叫父类,派生类又叫子类; 二.继承方式 继承方式分为三种: 1.public继承 2.protected继承 3.private继承 基类成员与继承方式的关系共有9种,见下表: 虽然说是有9种,但其实最常用的还…

MySQL 8.0详细安装配置教程

一. 前言 MySQL是目前最为流行的开源数据库产品,是完全网络化跨平台的关系型数据库系统。它起初是由瑞典MySQLAB公司开发,后来被Oracle公司收购,目前属于Oracle公司。因为开源,所以任何人都能从官网免费下载MySQL软件&#xff0c…

Jmeter接口/性能测试,Jmeter使用教程(超细整理)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、线程组 线程组…

【unity】ShaderGraph学习笔记

【unity】ShaderGraph学习笔记 创建ShaderGraph 创建URP的shaderGraph文件 在Project面板里Create→ShaderGraph→URP→这里主要有几个选项 Lit Shader Graph:有光照三维着色器 Unlit Shader Graph:无光照三维着色器 Sprite Custom Lit Shader Gra…

Flutter 调试工具篇 | 壹 - 使用 Flutter Inspector 分析界面

theme: cyanosis 1. 前言 很多朋友可能在布局过程中、或者组件使用过程中,会遇到诸如颜色、尺寸、约束、定位等问题,可能会让你抓耳挠腮。俗话说,磨刀不误砍柴工,会使用工具是非常重要的,其实 Flutter 提供了强大的调试…

Kafka入门到起飞系列 - 副本机制,什么是副本因子呢?

我们一直在讲一个主题会有多个分区,这多个分区可以分布在一台服务器上,也可以分布在多台服务器上,还可以增加分区(Kafka目前只支持分区),这是Kafka提供的一种横向扩展的手段 比如我们创建了一个主题&#x…

机器学习:异常检测

问题定义 anomaly,outlier, novelty, exceptions 不同的方法使用不同的名词定义这类问题。 应用 二分类 假如只有正常的数据,而异常的数据的范围非常广的话(无法穷举),二分类这些不好做。另外就…

MySQL数据库配置及创建用户和授权

注意: 都是基于MySQL8.0以上版本 1、检查是否安装过sql [rootlocalhost ~]# rpm -[qa](https://so.csdn.net/so/search?qqa&spm1001.2101.3001.7020) | grep mysql[rootlocalhost ~]# rpm -qa | grep [mariadb](https://so.csdn.net/so/search?qmariadb&…

左值引用与右值引用的区别?右值引用的意义?

左值引用与右值引用的区别?右值引用的意义? 1 区别1.1 功能差异1.2 左值引用1.3 右值引用1.3.1 实现移动语义1.3.2 实现完美转发 2 引用的作用3 区分左值和右值3.1 左值3.2 右值 1 区别 左值引用是对左值的引用;右值引用是对右值的引用。 &…

04 http连接处理(上)

基础知识&#xff1a;epoll、http报文格式、状态码和有限状态机 代码&#xff1a;对服务端处理http请求的全部流程进行简要介绍&#xff0c;然后结合代码对http类及请求接收进行详细分析。 epoll epoll_create函数 #include <sys/epoll.h> int epoll_create(int size)…

回归预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络多输入单输出回归预测

回归预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现TCN-BiLSTM时间卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现TCN-BiLSTM时间卷积…

CleanMyMac X4.14.1中文版如何清理 Mac系统?CleanMyMac 真的能断网激活吗?

CleanMyMac X4.14.1中文版如何清理 Mac系统&#xff1f;Mac系统在使用过程中都会产生大量系统垃圾&#xff0c;如不需要的系统语言安装包&#xff0c;视频网站缓存文件&#xff0c;mac软件卸载残留的注册表等。 随着时间推移&#xff0c;mac系统垃圾就会越来越多&#xff0c;电…

美团小图币代挂教程

登陆美团官网获取对应的cookie 美团官网&#xff0c;点击右上角登陆对应账号。登陆成功后使用f12来获取 cookie 此时如果没有任何数据&#xff0c;点击网页刷新。找到如下的网络请求 赋值cookie项的全部内容&#xff0c;此时已经获取到对应账号的cookie 使用cookie登陆代挂…