Flutter系列博客—09 EventChannel實現原生與Flutter通信(一)

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.successevents.error 分別會調用 Flutter 的對應方法。

其中 error 的參數對應 Flutter 的 PlatformException 的參數。

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

這裡通過廣播的方式將電量狀態變化發送給 Flutter。

效果如下:

Flutter系列博客—09 EventChannel實現原生與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;

}
/<dynamic>/<dynamic>/<dynamic>

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

那怎麼實現呢?

欲知詳情,且聽下回講解

Flutter系列博客—09 EventChannel實現原生與Flutter通信(一)

本文源碼位置:

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


分享到:


相關文章: