前言

紧接着上一篇,这一篇我们讲一下原生怎么给 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 直接实现。

那怎么实现呢?

欲知详情,且听下回讲解

本文源码位置:

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 通信(一)的更多相关文章

  1. Flutter 即学即用系列博客——09 MethodChannel 实现原生与 Flutter 通信(二)

    前言 上一篇我们讲解了如何通过 EventChannel 实现 Android -> Flutter 的通信. 并且也看到了 Flutter 内部 EventChannel 源码也是对 Meth ...

  2. Flutter 即学即用系列博客——03 在旧有项目引入 Flutter

    前言 其实如果打算在实际项目中引入 Flutter,完全将旧有项目改造成纯 Flutter 项目的可能性比较小,更多的是在旧有项目引入 Flutter. 因此本篇我们就说一说如何在旧有项目引入 Flu ...

  3. Flutter 即学即用系列博客总结篇

    前言 迟到的总结篇,其实大家看我之前发的系列博客最后一篇,发文时间是 3 月 29 日.距离现在快两个月了. 主要是因为有很多事情在忙,所以这篇就耽搁了. 今天终于可以跟大家会面了. 系列博客背景 F ...

  4. Flutter 即学即用系列博客——05 StatelessWidget vs StatefulWidget

    前言 上一篇我们对 Flutter UI 有了一个基本的了解. 这一篇我们通过自定义 Widget 来了解下如何写一个 Widget? 然而 Widget 有两个,StatelessWidget 和 ...

  5. Flutter 即学即用系列博客——04 Flutter UI 初窥

    前面三篇可以算是一个小小的里程碑. 主要是介绍了 Flutter 环境的搭建.如何创建 Flutter 项目以及如何在旧有 Android 项目引入 Flutter. 这一篇我们来学习下 Flutte ...

  6. Flutter 即学即用系列博客——08 MethodChannel 实现 Flutter 与原生通信

    背景 前面我们讲了很多 Flutter 相关的知识点,但是我们并没有介绍怎样实现 Flutter 与原生的通信. 比如我在 Flutter UI 上面点击了一个按钮,我希望原生做一些处理,那么原生怎么 ...

  7. Flutter 即学即用系列博客——06 超实用 Widget 集锦

    本篇文章我们来讲讲一些比较常用的 Widget. 大家验证的时候使用下面的代码替换 main.dart 代码,然后在 //TODO 语句返回下面常用 Widget 示例的代码. import 'pac ...

  8. Flutter 即学即用系列博客——02 一个纯 Flutter Demo 说明

    前言 上一篇文章我们搭建好了 Flutter 的开发环境. Flutter 即学即用--01 环境搭建 这一篇我们通过 Flutter 的一个 Demo 来了解下 Flutter. 开发系统:MAC ...

  9. Flutter 即学即用系列博客——10 混淆

    前言 之前的博客我们都是在 debug 的模式下进行开发的. 实际发布到市场或者给到用户的都是 release 包. 而对于 Android 来说,release 包一个重要的步骤就是混淆. Andr ...

随机推荐

  1. linux清除全屏快捷键(Ctrl+L)

    Linux用户基本上都习惯使用clear命令或Ctrl+L组合快捷键来清空终端屏幕.这样做其实并没有真正地清空屏幕,但当用鼠标向上滚时,你仍然能看到之前的命令操作留下来的输出.

  2. 汽车之家汽车品牌Logo信息抓取 DotnetSpider实战[三]

    一.正题前的唠叨 第一篇实战博客,阅读量1000+,第二篇,阅读量200+,两篇文章相差近5倍,这个差异真的令我很费劲,截止今天,我一直在思考为什么会有这么大的差距,是因为干货变少了,还是什么原因,一 ...

  3. Spire高效稳定的.NET组件

    年末将至,又到了一年一度的收集发票时间,平时零零碎碎的花钱都是不在意开发票,现在好了,到处找发票来报销,简直头大, 东拼西凑,终于搞定了全部发票,大伙多余的发票,麻烦艾特我一下啊,不限日期,能开发票的 ...

  4. 递归一个List<T>,可自己根据需要改造为通用型。

    /// <summary> /// 递归一个List<ProvinceOrg> /// </summary> /// <returns></ret ...

  5. Android WebView 缓存

    android很多情况是使用webView用来显示界面,但是webview的加载速度略慢,想让这个webview更快一些所以需要使用缓存,在没有更新的时候使用缓存技术来提高速度.总体来讲有两个方案可以 ...

  6. Android 切换横竖屏

    一个项目一般会自己先定义项目是横屏还是竖屏但是也有可以横屏和竖屏之间切换的activty. 切换横竖屏的方法: //判断当前屏幕方向if(getRequestedOrientation() == Ac ...

  7. Android之PhotoView使用

    文章大纲 一.什么是PhotoView二.代码实战三.项目源码下载 一.什么是PhotoView   一款 ImageView 展示框架,支持缩放,响应手势,位于图片排行榜的第五位,PhotoView ...

  8. 配置Asp.Net Web项目NLog配置文件的位置

    在使用NLog在asp.net项目中发现,如果想单独配其配置文件的位置时没有像Log4Net的特性配置方案,可以使其提供的 XmlLoggingConfiguration类来初始化: 见:https: ...

  9. gitbook 入门教程之环境要求

    gitbook 是基于 node.js 的命令行工具,首先需要安装并配置好 node.js 环境,然后才能安装gitbook 相关工具. 由于安装工具全部都是国外网站,因此速度可能会很慢,也可能需要F ...

  10. 2019-01-29 VS Code创建自定义Python代码片段

    续前文[日常]Beyond的歌里最多是"唏嘘"吗? - Python分词+词频最后的想法, 发现VS Code支持用户自定义代码片段: Creating your own snip ...