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

news2024/10/1 7:38:15

前言

上一篇博客主要介绍了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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频文件批量添加字幕内容需要如何快速操作

有时候我们在剪辑视频的过程中,想要给视频素材添加上一些文字说明,需要如何操作呢?为了提高剪辑效率,今天小编来分享教学,教你如何才能批量地给视频素材添加滚动字幕,一起来看看具体的方法介绍吧。 我们先打…

【C++】-模板进阶(让你更好的使用模板创建无限可能)

💖作者:小树苗渴望变成参天大树🎈 🎉作者宣言:认真写好每一篇博客💤 🎊作者gitee:gitee✨ 💞作者专栏:C语言,数据结构初阶,Linux,C 动态规划算法🎄 如 果 你 …

删除主表 子表外键没有索引的性能优化

整个表147M,执行时一个CPU耗尽, buffer gets 超过1个G, 启用并行也没有用 今天开发的同事问有个表上的数据为什么删不掉?我看了一下,也就不到100000条数据,表上有外键,等了5分钟hang在那里&…

固态硬盘种类

有三个层次,同一个词可能有多层意思,要注意区分。 一、接口 也叫插槽,插口。就是连接设备的地方。 能够插固态硬盘的插槽有:sata插槽,pcie插槽,m.2插槽,u.2插槽 (一)sat…

模拟量输出FC S_RTI(信捷C语言源代码)

模拟量输出FC SCL源代码请查看下面博客: PLC模拟量输出 模拟量转换FC S_RTI_博途模拟量转换指令_RXXW_Dor的博客-CSDN博客1、本文主要展示西门子博途模拟量输出转换的几种方法, 方法1:先展示下自编FC:计算公式如下:intput intput Real ISH Real //工程量上限 ISL Real //工…

Java中的equals方法详解:比较方法

1、equals方法的背景 在Java中,equals方法是Object类的一个方法,用于比较两个对象是否相等。 Java中有两种比较对象的方法:运算符和equals方法。 运算符用于比较两个对象的引用,如果它们指向的是同一个对象,则返回t…

继承-菱形继承

继承 继承是类设计层次的复用 继承方式与访问限定符 限定了啥? 1.根据表中我们可以看到 基类的私有成员在子类不可见,但还是被继承了下来 2.根据继承方式和成员在基类的访问限定符小的那个来决定了子类访问基类成员的访问方式 例如如果是public继承&a…

甄云库存管理解决方案 ,助力企业库存高效运转起来

导语 近年来,在降低成本、提高工作效率和满足用户需求等多重压力下,许多企业也开始重视非生产物资的库存管理,如办公设备、劳保用品、电子设备、维修工具、实验耗材。这些物资往往品类繁多、采购频率较高,占用了企业大量的管理时…

quartus工具篇——PLL IP核的使用

quartus工具篇——PLL IP核的使用 1、PLL简介 PLL(Phase-Locked Loop,相位锁环)是FPGA中非常重要的时钟管理单元,其主要功能包括: 频率合成 - PLL可以生成比输入时钟频率高的时钟信号。频率分频 - PLL也可以输出分频后的较低频率时钟。减小时钟抖动 - PLL可以过滤输入时钟中…

内存映射学习笔记

文章目录 内存映射原理函数定义mmap函数munmap函数 注意事项应用进程间通信文件复制 匿名映射 内存映射原理 将磁盘中的文件,映射到内存,通过内存修改文件。 函数定义 mmap函数 操作映射区必须要有 读权限 munmap函数 首地址 长度一致。 注意事项 可…

第一章:STC:一种用于弱监督语义分割的简单到复杂框架

0.摘要 近年来,由于深度卷积神经网络(DCNNs)的发展,语义目标分割取得了显著的改进。训练这样一个DCNN通常依赖于大量具有像素级分割掩码的图像,并且在财务和人力方面标记这些图像非常昂贵。在本文中,我们提…

javascript 7种继承-- 原型式继承分析(4)

文章目录 概要继承的进化史技术名词解释原型式继承原型式继承1原型式继承2对比图 原型链继承 vs 原型式继承案列分析源代码解析效果图小结优点缺点 概要 这阵子在整理JS的7种继承方式,发现很多文章跟视频,讲解后都不能让自己理解清晰,索性自…

【前端学java】JAVA中的packge与import

packge与import示例 Java中,使用package关键字来声明一个类所属的包: package myapp;public class MyClass {// 类的实现... }上述代码中,MyClass类被声明为属于myapp的包。在其他的代码中使用该类时,需要使用完整的包名来引用它…

学习DT材质基础

Lambert材质和常用颜色属性 Maya材质的发光属性 Maya材质的光线跟踪属性 看不见阴影是因为背景用错材质了 MAYA矢量渲染 各向异性材料(看高光) 渐变材质 开启光线跟踪 表面着色器材质

微服务——Docker

docker与虚拟机的区别 首先要知道三个层次 硬件层:计算机硬件 内核层:与硬件交互,提供操作硬件的指令 应用层: 系统应用封装内核指令为函数,便于程序员调用。用户程序基于系统函数库实现功能。 docker在打包的时候直接把应用层的函数库也进行打包&a…

【GeoDa实用技巧100例】015:Geoda构建箱线图

文章目录 一、箱线图介绍二、Geoda制作箱形图三、箱形图与箱形地图的链接一、箱线图介绍 箱形图,也称箱线图(Box and Whisker Diagram)、箱图、盒须图、盒式图和盒形图等,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。箱形图是由美国著名统计学家图基在…

vue3-组件中的变化

1. 路由 1. 安装指令:npm i vue-routernext 2. 创建路由:createRouter2. 异步组件(defineAsyncComponent) defineAsyncComponent 是用于定义异步组件的函数。defineAsyncComponent 接受一个工厂函数作为参数,这个工厂…

opencv-22 图像几何变换01-缩放-cv2.resize()(图像增强,图像变形,图像拼接)

什么是几何变换? 几何变换是计算机图形学中的一种图像处理技术,用于对图像进行空间上的变换,而不改变图像的内容。这些变换可以通过对图像中的像素位置进行调整来实现。 常见的几何变换包括: 平移(Translation&#x…

力扣热门100题之无重复字符的连续子串【中等】

题目描述 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2: 输入: s “bbbbb” 输出: 1 解释: 因为无重复字符的最长子…

Java8实战-总结6

Java8实战-总结6 通过行为参数化传递代码对付啰嗦匿名类第五次尝试:使用匿名类第六次尝试:使用Lambda表达式第七次尝试:将List类型抽象化 真实的例子用Comparator来排序 通过行为参数化传递代码 对付啰嗦 人们不愿意用那些很麻烦的功能或概…