Flutter(三)Flutter与Android原生Activity交互及传递数据

推荐阅读

Flutter(二)Android集成Flutter项目并实现跳转到 Flutter 界面  

Flutter(一) 安装部署与认识Dart语言


目录

前言

一、Platform Channel

二、MethodChannel

三、Flutter返回上一页


前言

上一篇中,学习了 Android 原生集成 Flutter 并实现了页面跳转本篇将要学习Flutter与Activity之间的数据交互。


一、Platform Channel

Flutter 定义了三种不同的 Channel;但无论是传递方法还是传递事件,其本质上都是数据的传递;

  • MethodChannel:用于传递方法调用。
  • EventChannel:用于数据流的通信;用于Flutter和平台端进行事件监听、取消等。
  • BasicMessageChannel:用于传递字符串和半结构化的信息;用于Flutter和平台端进行消息数据交换时。

      每种 Channel 均包含三个成员变量;

  • name:代表 Channel 唯一标识符,Channel 可以包含多个,但 name 为唯一的;
  • messager:代表消息发送与接收的工具 BinaryMessenger
  • codec:代表消息的编解码器;

这里我,主要介绍一下MethodChannel的使用,它也是我们开发中最常用的。

 


二、MethodChannel

在Flutter中调用MethodChannel 的 invokeMethod 方法实现跳转及参数传递到原生Activity页面。原生Activity页面调用MethodChannelsetMethodCallHandler方法实现方法回调,接受Flutter传递的消息。

1、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();
        }
    }

2、Flutter代码

在Flutter端同样需要定义一个MethodChannel,使用MethodChannel需要引入services.dart包,Channel名称要和Android端定义的相同。点击按钮执行调用invokeMethod(),该方法有2个参数。第1个是呼应Android端的methodCall.method获取到的方法名。第2个是方法的参数,在Android端通过methodCall.arguments()/argument()获取到所有参数或指定名称的参数。

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返回上一页

原生Activity中嵌套FlutterView页面,类似于嵌套一个WebView,每个Flutter页面对应着一个route路由地址,就相当于Url链接地址。我们知道WebView有goBack()方法返回上一个网页;那么,在Flutter页面如何实现返回上一页呢。

实现思路如下:

Flutter调用Navigator.canPop(context)判断是否可以返回,true 就调用Navigator.of(context).pop()返回,false 则说明当前已经是第一个页面了,就返回到Activity。

首先,在Flutter页面中添加一个按钮,点击按钮跳转到SecondPage页面。

RaisedButton(
    child: Text('跳转Flutter页面'),
    onPressed: () {
      Navigator.of(context).push(MaterialPageRoute(builder: (context) {
        return SecondPage();
      }));
    }
),

 然后,定义MethodChannel和MethodCallHandler回调,调用Navigator.canPop(context) 进行判断,是Flutter返回上一页还是回到Activity原生页面。

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);
}

在Android端,重写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回调,如果当前Flutter页面是第一个时调用该方法直接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;
}

参考地址:

Flutter 49: 图解 Flutter 与 Android 原生交互;

Flutter学习小计:Android原生项目引入Flutter;

猜你喜欢

转载自blog.csdn.net/csdn_aiyang/article/details/106875108