前言

紧接着上一篇,这一篇我们讲一下原生怎么给 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. 复仇者联盟3热映,我用python爬取影评告诉你它都在讲什么

    Python(发音:英[?pa?θ?n],美[?pa?θɑ:n]),是一种面向对象.直译式电脑编程语言,也是一种功能强大的通用型语言,已经具有近二十年的发展历史,成熟且稳定.它包含了一组完善而且容易理 ...

  2. python设计模式-观察者

    定义: 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖的对象都会得到通知并被自动更新. 观察者模式是对象的行为模式,又叫发布-订阅(pubish/subscribe)模式,模型 ...

  3. MIP 问题解决方案大全(2018-06更新)

    在 MIP 推出后,我们收到了一些站长的疑问.现将常见问题整理出来,帮助大家了解 MIP 的知识. 一.MIP 认知类问题 二.改造前准备 三.前端改造,组件使用 四.提交生效 五.MIPCache ...

  4. ADB环境搭建 -- For Windows 10

    一.安装 ADB: ADB下载链接:http://adbshell.com/upload/adb.zip       ADB官网:http://adbshell.com/ 下载好后,建议直接把文件解压 ...

  5. C#之Socket的简单使用

    Socket是一种通信TCP/IP的通讯接口,也就是HTTP的抽象层,就是Socket在Http之上,Socket也就是发动机.实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又 ...

  6. Python:游戏:五子棋之人机对战

    本文代码基于 python3.6 和 pygame1.9.4. 五子棋比起我之前写的几款游戏来说,难度提高了不少.如果是人与人对战,那么,电脑只需要判断是否赢了就可以.如果是人机对战,那你还得让电脑知 ...

  7. Postgre Sql获取最近一周、一月、一年日期函数

    使用Postgre Sql获取近一周.一年.一月等系统函数调用如下,使用方面相对于Ms Sql server 容易了许多. --当前时间 select now(); --current_timesta ...

  8. 第8章 动态客户端注册 - IdentityModel 中文文档(v1.0.0)

    OpenID Connect动态客户端注册的客户端库是作为HttpClient扩展方法提供的. 以下代码发送注册请求: var client = new HttpClient(); var respo ...

  9. 20190402-display展现、float浮动

    目录 1.display展现 dispaly:"none | block | inline | inline-block | list-item | run-in(主流浏览器不支持) | t ...

  10. K3数据字典备查

    select distinct f.FNumber as 系统代码, f.FName AS 系统名称,  d.FTableName AS 表名,d.FDescription AS 表说明,a.[nam ...