紧接着上一篇,这一篇我们讲一下原生怎么给 Flutter 发信号,即原生-> Flutter
还是通过 Flutter 官网的 Example 来讲解。
接着上一次,这一次我们让原生主动将电池的充电状态发送给 Flutter 并在界面显示。
步骤如下。
我们在原先基础上增加一列用于显示文本。
String _chargingStatus = 'Battery status: unknown.';Text(_chargingStatus),
我们在 _BatteryWidgetState 里面加入下面变量:
static const EventChannel eventChannel = EventChannel('samples.flutter.io/charging');
samples.flutter.io/charging 可以自己指定,一般保证唯一,所以 samples 实际使用可以替换为包名。主要是要跟原生对应即可。
@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;
这个转换语句才可以。
private static final String CHARGING_CHANNEL = "samples.flutter.io/charging";
注意需要跟 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