flutter插件基础之调用EventChannel的简单使用(三)

本篇开始之前,废话不多说,先上效果如下所示:

flutter和原生互传效果.gif

首先,本篇开始讲解EventChannel的使用,


千里之行,始于足下

三.EventChannel的使用

上篇中,我们提到通过MethodChannel的实现可以使flutter端可以随时随地的调用到原生端的如设备版本号,电量等系统信息,并及时返回给flutter端;但是诸如原生端声音音量的改变,电池电量的减少(如电池电量少于20%)时要主动通知到flutter端,MethodChannel并没有这样的能力,所以此时就需要引入EventChannel来解决此问题。

1.EventChannel基本介绍

通过前文EventChannel和MethodChannel的实现流程的异同点分析,我们知道了EventChannel的实现主要分为以下2个步骤,即为如何设置flutter的监听以及原生调用flutter的流程:

1.1.flutter监听流程

首先我们可以在flutter的example/lib/more_Params_page.dart 类或者插件类 lib/flutter_plugin_demo2.dart 类中定义事件响应通道_eventChannel和要监听的事件流对象_streamSubscription,如下所示:

static const EventChannel? _eventChannel = EventChannel("flutter_show_alert/event");
StreamSubscription<dynamic>? _streamSubscription;

在当前类的initState初始化方法中加入需要监听的代码为:

_streamSubscription =  _eventChannel?.receiveBroadcastStream().listen((event) {
  final Map<dynamic,dynamic> map = event;
  String? key = map["key"];
  int? value = map["value"];
  print("handle on ---$key---$value");
  if(map["key"] == "changeVoice"){
  }
  else if(map["key"] == "getCount") {
    setState(() {
            productCount = value;
          });
  }
},onError: errorEventListen,onDone:doneEventListen,) as StreamSubscription;

分别实现对应的 errorEventListen 和 doneEventListen 方法后,如此在flutter端监听的内容设置完毕。

注意:为了更多减少流程,这里是以比较直接的在flutter代码的example/lib/more_Params_page.dart中加入监听原生端代码为例的;
当然,实际开发中可能监听的内容不止一个,建议在插件类 lib/flutter_plugin_demo2.dart类中进行监听,然后根据不同的key分发给flutter代码层,这样会比较好理解一些。

1.2.原生(以安卓为例)调用流程

当flutter端监听的准备工作完成后,需要在安卓原生类FlutterPluginDemo2Plugin.java中加入需要调用的代码,同样主要分为3个步骤。

1.事件派发对象和派发流的定义
定义事件派发对象和派发流代码如下,在派发流的onListen方法中把系统获取事件派发对象赋值给我们定义的事件派发对象,当系统取消事件派发流时,则把事件派发对象置空即可;

// 事件派发对象
private  EventChannel.EventSink eventSink = null;
// 事件派发流
private  EventChannel.StreamHandler streamHandler = new  EventChannel.StreamHandler(){
  @Override
  public void onListen(Object arguments, EventChannel.EventSink events) {
    eventSink = events;
  }

  @Override
  public void onCancel(Object arguments) {
    eventSink = null;
  }
};

2.派发流的初始化和注册

// 初始化事件
EventChannel eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), "flutter_show_alert/event");
eventChannel.setStreamHandler(streamHandler);

在onAttachedToEngine 方法中对EventChannel对象进行初始化,保证这里的"flutter_show_alert/event"
要和flutter中的保持一致
,并把我们定义的事件派发流设置给EventChannel去进行管理。

3.事件派发流回传flutter

在需要的地方执行

eventSink.success(map);

即可把要传递的对象回传给flutter。
当然,需要注意的是,在执行eventSink之前需要判空,避免eventSink对象被取消时时,导致崩溃。

2.借助EventChannel实现音量实时监听功能

如开篇所示gif效果图,这里以flutter中设置监听,在原生的iOS端点击音量键后把音量值实时传递给flutter,并在flutter中进行显示的功能

2.1.Flutter端

在example/lib/more_Params_page.dart类中,设置监听的内容(这里只关心changeVoice的key

// 方法2:在需要调用的地方设置监听(各自派发)
_streamSubscription =  _eventChannel?.receiveBroadcastStream().listen((event) {
  final Map<dynamic,dynamic> map = event;
  String? key = map["key"];
  // int? value = map["value"];
  print("handle on ---$key---${map["value"]}");
  if(map["key"] == "changeVoice"){
    setState(() {
      nowVoice = map["value"];
    });
  }
  else if(map["key"] == "getCount") {
    setState(() {
            productCount = map["value"];
          });
  }
},onError: errorEventListen,onDone:doneEventListen,) as StreamSubscription;

2.2.Native(iOS)端

在 FlutterPluginDemo2Plugin.m类中编写代码如下所示:

1.在registerWithRegistrar方法中同MethodChannel对象,初始化注册EventChannel对象如下

FlutterEventChannel *eventChannel = [FlutterEventChannel eventChannelWithName:@"flutter_show_alert/event"  binaryMessenger:[registrar messenger]];
    [eventChannel setStreamHandler:instance];

注意:这里的instance是当前类的对象,为了后续可能有其他地方用到当前类,所以这里用单例实现获取该对象

2.遵循FlutterStreamHandler类协议
实现其onListenWithArguments和onCancelWithArguments方法(具体实现同安卓)

3.音量按键通知的监听
在onListenWithArguments方法中设置iOS的音量通知代码如下所示

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(systemVolumChanged:)name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];

4.监听音量变化时把音量值回传给flutter

在音量键通知回调方法中执行

 self.eventSink(dic);

把相关信息包装在dic对象中,回传给flutter进行实时显示音量值大小

注意:在测试修改原生音量的情况下,iOS的设备记得用真机来调测,因为有段时间没搞了,竟然在这个问题上费了很长时间。😭😭

可以看到安卓和iOS相比而言,基本大同小异,整体来说安卓实现3个步骤,iOS是4个步骤,主要问题在于安卓的派发流的定义和FlutterStreamHandler协议实现在同一步骤之中,而iOS则分了2步,当然主要是因为flutter底层中对iOS这块接口的定义是采用协议的形式,如果采用block的方式,也是可以实现同安卓的3步。

好了,通过本篇对EventChannel的讲解说明,可以发现EventChannel主要目的是实现原生可随时通知到flutter,而上篇的MethodChannel对象则实现的是flutter调用安卓的功能,如此二者形成了一个闭环,可以互相调用对方的方法,如此很自然的,就会想到原生擅长什么,flutter擅长什么,二者是不是可以融合在一起,很自然的混合开发就出现了。
不过别着急,在我们研究混合开发之前我们先解决另一个小问题,发现没,现在做到的是flutter和native之间数据的打通互传,但是当把原生view界面如何在flutter中显示,比如常见的地图,直播类的原生界面如何在flutter上完美展现,这个问题,我们下次再来研究。

flutter插件基础之调用MethodChannel的基本使用(二)

本篇,完~~

推荐阅读更多精彩内容