Flutter 即学即用系列博客——09 EventChannel 实现原生与 Flutter 通信(一)

本文基于Flutter官网示例,讲解原生向Flutter发送信号的实现方法。包括Flutter界面修改、定义EventChannel、实现监听及回调方法,原生定义和创建EventChannel并发送内容。还提到原生与Flutter通信也可用MethodChannel实现,后续将讲解详情。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

紧接着上一篇,这一篇我们讲一下原生怎么给 Flutter 发信号,即原生-> Flutter

还是通过 Flutter 官网的 Example 来讲解。

案例

接着上一次,这一次我们让原生主动将电池的充电状态发送给 Flutter 并在界面显示。

步骤如下。

1. Flutter 界面修改

我们在原先基础上增加一列用于显示文本。

String _chargingStatus = 'Battery status: unknown.';
Text(_chargingStatus),
复制代码
2. Flutter 定义 EventChannel

我们在 _BatteryWidgetState 里面加入下面变量:

static const EventChannel eventChannel = EventChannel('samples.flutter.io/charging');
复制代码

samples.flutter.io/charging 可以自己指定,一般保证唯一,所以 samples 实际使用可以替换为包名。主要是要跟原生对应即可。

3. Flutter 在 initState 实现 EventChannel 监听并实现对应回调方法
  @override
  void initState() {
    super.initState();
    eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
  }

  void _onEvent(Object event) {
    setState(() {
      _chargingStatus =
      "Battery status: ${event == 'charging' ? '' : 'dis'}charging.";
    });
  }

  void _onError(Object error) {
    setState(() {
        PlatformException exception = error;
        _chargingStatus = exception?.message ?? 'Battery status: unknown.';
    });
  }
复制代码

可以看到如果原生发送 charging 显示 charging,否则显示 discharging。

当然错误显示的是原生发送过来的错误信息。

注意这里如果要获取到错误信息,需要通过

PlatformException exception = error;
复制代码

这个转换语句才可以。

4. 原生定义 EventChannel
private static final String CHARGING_CHANNEL = "samples.flutter.io/charging";
复制代码

注意需要跟 Flutter 的一一对应。

5. 原生创建 EventChannel 并通过 StreamHandler 的 EventSink 发送内容给 Flutter
new EventChannel((FlutterView) flutterView, CHARGING_CHANNEL).setStreamHandler(
        new EventChannel.StreamHandler() {

            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
            }

            @Override
            public void onCancel(Object arguments) {
            }
        }
);
复制代码

具体到这里为:

new EventChannel((FlutterView)flutterView, CHARGING_CHANNEL).setStreamHandler(
        new EventChannel.StreamHandler() {
            private BroadcastReceiver chargingStateChangeReceiver;
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                chargingStateChangeReceiver = createChargingStateChangeReceiver(events);
                registerReceiver(
                        chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
            }

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

private BroadcastReceiver createChargingStateChangeReceiver(final EventChannel.EventSink events) {
    return new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);

            if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
                events.error("UNAVAILABLE", "Charging status unavailable", null);
            } else {
                boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                        status == BatteryManager.BATTERY_STATUS_FULL;
                events.success(isCharging ? "charging" : "discharging");
            }
        }
    };
}
复制代码

这里的 events.successevents.error 分别会调用 Flutter 的对应方法。

其中 error 的参数对应 Flutter 的 PlatformException 的参数。

PlatformException({
  @required this.code,
  this.message,
  this.details,
}) : assert(code != null);
复制代码

这里通过广播的方式将电量状态变化发送给 Flutter。

效果如下:

扩展

其实我们点击 Flutter 的 EventChannel,会看到源码里面的 receiveBroadcastStream 方法是对 MethodChannel 做了封装。

Stream<dynamic> receiveBroadcastStream([dynamic arguments]) {
    final MethodChannel methodChannel = MethodChannel(name, codec);
    StreamController<dynamic> controller;
    controller = StreamController<dynamic>.broadcast(onListen: () async {
      BinaryMessages.setMessageHandler(name, (ByteData reply) async {
        if (reply == null) {
          controller.close();
        } else {
          try {
            controller.add(codec.decodeEnvelope(reply));
          } on PlatformException catch (e) {
            controller.addError(e);
          }
        }
        return null;
      });
      try {
        await methodChannel.invokeMethod('listen', arguments);
      } catch (exception, stack) {
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: stack,
          library: 'services library',
          context: 'while activating platform stream on channel $name',
        ));
      }
    }, onCancel: () async {
      BinaryMessages.setMessageHandler(name, null);
      try {
        await methodChannel.invokeMethod('cancel', arguments);
      } catch (exception, stack) {
        FlutterError.reportError(FlutterErrorDetails(
          exception: exception,
          stack: stack,
          library: 'services library',
          context: 'while de-activating platform stream on channel $name',
        ));
      }
    });
    return controller.stream;
  }
复制代码

所以其实原生-> Flutter 的通信也是可以用 MethodChannel 直接实现。

那怎么实现呢?

欲知详情,且听下回讲解

本文源码位置:
github.com/nesger/Flut…

参考链接:

flutter.dev/docs/develo…
github.com/flutter/flu…

更多阅读:
Flutter 即学即用系列博客
Flutter 即学即用系列博客——01 环境搭建
Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
Flutter 即学即用系列博客——04 Flutter UI 初窥
Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
Flutter 即学即用系列博客——06 超实用 Widget 集锦
Flutter 即学即用系列博客——07 RenderFlex overflowed 引发的思考
Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信

Flutter & dart
dart 如何优雅的避空
Flutter map 妙用及 .. 使用

转载于:https://juejin.im/post/5c94d35df265da612647bba0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值