上一篇中:Flutter 使用AndroidStudio并集成Flutter界面_flutter3.0 android跳转到flutter界面-优快云博客,学习了 Android 原生集成 Flutter 并实现了页面跳转,本篇将要学习Flutter与Activity之间的数据交互。
Platform Channel 跨平台通讯
三种不同的 Channel:
- MethodChannel:用于Flutter和原生方法映射调用;
- EventChannel:用于Flutter和Native进行事件监听、取消等。
- BasicMessageChannel:用于Flutter和Native进行消息数据交换时。
但无论是传递方法、事件,其本质上都是数据的传递。每种 Channel 均包含三个成员变量:
- name:代表 Channel 唯一标识符,Channel 可以包含多个,但 name 是唯一的;
- messager:代表消息发送与接收的工具 BinaryMessenger;
- codec:代表消息的编解码器;
BinaryMessenger
BinaryMessenger是PlatformChannel与Flutter端的通信的工具,其通信使用的消息格式为二进制格式数据,BinaryMessenger在Android中是一个接口,它的实现类为FlutterNativeView。
Codec
Codec是消息编解码器,主要用于将二进制格式的数据转化为Handler能够识别的数据。Flutter定义了两种Codec:
-
MessageCodec用于二进制格式数据与基础数据之间的编解码,BasicMessageChannel所使用的编解码器是MessageCodec。
-
MethodChannel和EventChannel所使用的编解码均为MethodCodec。
Handler
Flutter定义了三种类型的Handler,它们与PlatformChannel类型一一对应,分别是MessageHandler、MethodHandler、StreamHandler。
使用PlatformChannel时,会为它注册一个Handler,PlatformChannel会将该二进制数据通过Codec解码为转化为Handler能够识别的数据,并交给Handler处理。当Handler处理完消息之后,会通过回调函数返回result,将result通过编解码器编码为二进制格式数据,通过BinaryMessenger发送回Flutter端。
MethodChannel
- Flutter中调用MethodChannel.invokeMethod()实现跳转及参数传递到原生Activity页面。
- 原生页面调用MethodChannel.setMethodCallHandler()接受Flutter传递的消息。
Android 代码
Android端创建MethodChannel需要传递2个参数。第1个是BinaryMessenger接口,代表消息信使,是消息发送与接收的工具;第二个参数是name,表示
Channel的名称,定义了final类型保证唯一,与Flutter的MethodChannel呼应上。
private static final String CHANNEL_NATIVE = "com.example.flutter/native";
private FlutterEngine flutterEngine;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_takeout);
flutterEngine = new FlutterEngine(this);
flutterEngine.getNavigationChannel().setInitialRoute("route1");
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
flutterView = new FlutterView(this);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
FrameLayout flContainer = findViewById(R.id.flutter_view);
flContainer.addView(flutterView, lp);
if (flutterEngine!=null){
flutterView.attachToFlutterEngine(flutterEngine);
}
MethodChannel nativeChannel = new MethodChannel(flutterEngine.getDartExecutor()
.getBinaryMessenger(), CHANNEL_NATIVE);
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
switch (methodCall.method) {
case "jumpToNative": // 跳转原生页面
if (methodCall.arguments != null) {
ToastUtil.show(TAG, methodCall.argument("message"));
} else {
ToastUtil.show(TAG,"回调参数为空");
}
startActivity(new Intent(TAG, MainPageActivity.class));
result.success("Activity -> Flutter 接收回调的返回值成功");
break;
default:
result.notImplemented();
break;
}
}
});
}
@Override
protected void onResume() {
super.onResume();
if (flutterEngine!=null){
flutterEngine.getLifecycleChannel().appIsResumed();
}
}
@Override
protected void onPause() {
super.onPause();
if (flutterEngine!=null){
flutterEngine.getLifecycleChannel().appIsInactive();
}
}
@Override
protected void onStop() {
super.onStop();
if (flutterEngine!=null){
flutterEngine.getLifecycleChannel().appIsPaused();
}
}
Flutter代码
使用MethodChannel需要引入services.dart
包,Channel名称要和Android端定义的相同。调用invokeMethod()。
class _MyHomePageState extends State<MyHomePage> {
static const nativeChannel = const MethodChannel('com.example.flutter/native');
String _result = '';
Future<void> _incrementCounter() async {
Map<String, dynamic> result = {'message': '我从Flutter页面回来了'};
try {
_result = await nativeChannel.invokeMethod('jumpToNative', result);
} on PlatformException catch (e) {
_result = "Failed: '${e.message}'.";
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title), ),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('传递结果:$_result',),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Flutter返回上一页:传递数据
Navigator.canPop(context)
判断是否可以返回,true 就调用返回,false 则说明当前已经是第一个页面了,就跳转到Activity。代码实例如下:
FlutterView页面添加按钮:跳转到SecondPage页面
RaisedButton(
child: Text('跳转Flutter页面'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return SecondPage();
}));
}
),
调用Navigator.canPop(context)
判断:
static const nativeChannel =const MethodChannel('com.example.flutter/native');
static const flutterChannel =const MethodChannel('com.example.flutter/flutter');
@override
void initState() {
super.initState();
Future<dynamic> handler(MethodCall call) async {
switch (call.method) {
case 'goBack':
if (Navigator.canPop(context)) { // 返回上一页
Navigator.of(context).pop();
} else {
nativeChannel.invokeMethod('goBack');
}
break;
}
}
flutterChannel.setMethodCallHandler(handler);
}
在Activity重写onBackPressed()
方法,将返回键的事件处理交给Flutter端。
private static final String CHANNEL_FLUTTER = "com.example.flutter/flutter";
@Override
public void onBackPressed() {
MethodChannel flutterChannel = new MethodChannel(flutterView, CHANNEL_FLUTTER);
flutterChannel.invokeMethod("goBack", null);
}
原生的MethodCallHandler回调,调用该方法直接finish掉Activity。
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
switch (methodCall.method) {
case "goBack":
// 返回上一页
finish();
break;
default:
result.notImplemented();
break;
}