Flutter 即学即用系列博客——09 EventChannel 实现原生与 Flutter 通信(一)
前言
紧接着上一篇,这一篇我们讲一下原生怎么给 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.success 和 events.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 直接实现。
那怎么实现呢?
欲知详情,且听下回讲解
本文源码位置:
https://github.com/nesger/FlutterSample/tree/feature/event_channel
参考链接:
https://flutter.dev/docs/development/platform-integration/platform-channels
https://github.com/flutter/flutter/tree/master/examples/platform_channel
更多阅读:
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 妙用及 .. 使用
Flutter 即学即用系列博客——09 EventChannel 实现原生与 Flutter 通信(一)的更多相关文章
- Flutter 即学即用系列博客——09 MethodChannel 实现原生与 Flutter 通信(二)
前言 上一篇我们讲解了如何通过 EventChannel 实现 Android -> Flutter 的通信. 并且也看到了 Flutter 内部 EventChannel 源码也是对 Meth ...
- Flutter 即学即用系列博客——03 在旧有项目引入 Flutter
前言 其实如果打算在实际项目中引入 Flutter,完全将旧有项目改造成纯 Flutter 项目的可能性比较小,更多的是在旧有项目引入 Flutter. 因此本篇我们就说一说如何在旧有项目引入 Flu ...
- Flutter 即学即用系列博客总结篇
前言 迟到的总结篇,其实大家看我之前发的系列博客最后一篇,发文时间是 3 月 29 日.距离现在快两个月了. 主要是因为有很多事情在忙,所以这篇就耽搁了. 今天终于可以跟大家会面了. 系列博客背景 F ...
- Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget
前言 上一篇我们对 Flutter UI 有了一个基本的了解. 这一篇我们通过自定义 Widget 来了解下如何写一个 Widget? 然而 Widget 有两个,StatelessWidget 和 ...
- Flutter 即学即用系列博客——04 Flutter UI 初窥
前面三篇可以算是一个小小的里程碑. 主要是介绍了 Flutter 环境的搭建.如何创建 Flutter 项目以及如何在旧有 Android 项目引入 Flutter. 这一篇我们来学习下 Flutte ...
- Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信
背景 前面我们讲了很多 Flutter 相关的知识点,但是我们并没有介绍怎样实现 Flutter 与原生的通信. 比如我在 Flutter UI 上面点击了一个按钮,我希望原生做一些处理,那么原生怎么 ...
- Flutter 即学即用系列博客——06 超实用 Widget 集锦
本篇文章我们来讲讲一些比较常用的 Widget. 大家验证的时候使用下面的代码替换 main.dart 代码,然后在 //TODO 语句返回下面常用 Widget 示例的代码. import 'pac ...
- Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明
前言 上一篇文章我们搭建好了 Flutter 的开发环境. Flutter 即学即用--01 环境搭建 这一篇我们通过 Flutter 的一个 Demo 来了解下 Flutter. 开发系统:MAC ...
- Flutter 即学即用系列博客——10 混淆
前言 之前的博客我们都是在 debug 的模式下进行开发的. 实际发布到市场或者给到用户的都是 release 包. 而对于 Android 来说,release 包一个重要的步骤就是混淆. Andr ...
随机推荐
- 深入css布局篇(3)完结 — margin问题与格式化上下文
深入css布局(3) - margin问题与格式化上下文 在css知识体系中,除了css选择器,样式属性等基础知识外,css布局相关的知识才是css比较核心和重要的点.今天我们来深入学习一下 ...
- Win10安装cygwin并添加apt-cyg
1.去Cygwin官网:https://www.cygwin.com/ 进入上图的install链接(下图),根据自己的电脑选择32位还是64位 我选择了一个32位的: 一直下一步下图: 163镜像链 ...
- 服务网关基于RPC的用法
企业为了保护内部系统的安全性,内网与外网都是隔离的,企业的服务应用都是运行在内网环境中,为了安全的考量,一般都不允许外部直接访问.API网关部署在防火墙外面,起到一层挡板作用,内部系统只接受API网关 ...
- 434个H5游戏源码
各种类型HTML5游戏,界面和JS均可供项目参考 下面是下载地址
- ASP.NET Core 实现带认证功能的Web代理服务器
引言 最近在公司开发了一个项目,项目部署架构图如下: 思路 如图中文本所述,公司大数据集群不允许直接访问外网,需要一个网关服务器代理请求,本处服务器A就是边缘代理服务器的作用. 通常技术人员最快捷的思 ...
- openJDK知识整理及概念
上周同事去听了阿里openJDK的讲座,收集整理了一下.随着Oracle 撒手,Java 8 官方支持时间持续到 2020 年 12 月:对商业用户(Commercial Users),2019 年 ...
- 《k8s-1.13版本源码分析》-调度优选
源码分析系列文章已经开源到github,地址如下: github:https://github.com/farmer-hutao/k8s-source-code-analysis gitbook:ht ...
- 关于数据库管理系统DBMS--关系型数据库(MySQL/MariaDB)
数据库的结构(3种):层次,网状,关系型(用的最多): DBMS的三层模型: 视图层:面向最终用户: 逻辑层:面向程序员或DBA: 物理层:面向系统管理员: 关系型数据库管理系统——RDBMS: 主要 ...
- Mapbox使用详解
一.简介: Mapbox致力于打造全球最漂亮的个性化地图. 在一次偶然的地图相关资料搜索过程中发现了一个很神奇又很漂亮的地图,这个地图支持高度自定义各种地图元素,比如,道路,水系,绿地,建筑物,背 ...
- 1、Linux命令随笔
1 Linux命令总结 2 3 man ==命令帮助; 4 help ==命令的帮助(bash的内置命令); 5 ls ==list,查看目录列表; 6 -ld:查看目录权限; 7 -l:(long) ...