Recommended reading
Flutter (2) Android integrates Flutter projects and jumps to the Flutter interface
Flutter (1) Installation, deployment and understanding of Dart language
Catalog
3. Flutter returns to the previous page
Preface
In the previous article, you learned about Android's native integrated Flutter and implemented page jumping. In this article, you will learn about data interaction between Flutter and Activity.
1. Platform Channel
Flutter defines three different Channel s; however, whether it is a delivery method or an event, it is essentially a transfer of data.
- MethodChannel: Used to pass method calls.
- EventChannel: Used for communication of data streams; used for event monitoring, cancellation, etc. on Flutter and platform.
- BasicMessageChannel: Used to convey string and semi-structured information; used for message data exchange between Flutter and the platform.
Each Channel contains three member variables;
- Name: Represents the Channel unique identifier. Channel can contain more than one, but name is unique;
- messager: A tool that represents the sending and receiving of messages, BinaryMessenger;
- Codec: a codec that represents a message;
Here I'm going to focus on the use of MethodChannel, which is also the most commonly used in our development.
2. MethodChannel
Call the invokeMethod method of MethodChannel in Flutter to jump and pass parameters to the native activity page.The native Activity page calls the MethodChannel's setMethodCallHandler method to implement a method callback that accepts the message passed by Flutter.
1. Android Code
Creating a MethodChannel on the Android side requires passing two parameters.The first is the BinaryMessenger interface, which represents the messenger and is the tool for sending and receiving messages; the second parameter is name, which represents the name of the Channel, defines the final type guarantees uniqueness, and corresponds to Flutter's 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": // Jump to Native Page if (methodCall.arguments != null) { ToastUtil.show(TAG, methodCall.argument("message")); } else { ToastUtil.show(TAG,"Callback parameter is empty"); } startActivity(new Intent(TAG, MainPageActivity.class)); result.success("Activity -> Flutter Receive callback return value successfully"); 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 Code
A MethodChannel also needs to be defined on the Flutter side, and it needs to be introduced using MethodChannelServices.dartPackage, Channel name should be the same as defined on Android side.Click the button to execute the call invokeMethod(), which has two parameters.The first one corresponds to the Android sideMethodCall.methodGet the method name.The second is the method's parameter, which is passed on the Android sideMethodCall.arguments()/argument() gets all the parameters or the parameters with the specified name.
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': 'From Flutter Page back'}; try { _result = await nativeChannel.invokeMethod('jumpToNative', result); } on PlatformException catch (e) { _result = "Failed: '$'."; } setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('Delivery results: $_result',), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
3. Flutter returns to the previous page
A nested FlutterView page in a native Activity is similar to a nested WebView, where each Flutter page corresponds to a route routing address, which is equivalent to a Url link address.We know that WebView has a goBack() method to return to the previous page; so how do you implement a return to the previous page on a Flutter page?
The ideas are as follows:
Flutter Call Navigator.canPop(context) To determine if it is possible to return, true callsNavigator.of(context). pop() returns, while false indicates that it is the first page and returns to Activity.
First, add a button to the Flutter page and click it to jump to the SecondPage page.
RaisedButton( child: Text('Jump Flutter page'), onPressed: () { Navigator.of(context).push(MaterialPageRoute(builder: (context) { return SecondPage(); })); } ),
Then, define MethodChannel and MethodCallHandler callbacks, call Navigator.canPop(context) to determine whether Flutter returns to the previous page or the Activity native page.
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)) { // Return to the previous page Navigator.of(context).pop(); } else { nativeChannel.invokeMethod('goBack'); } break; } } flutterChannel.setMethodCallHandler(handler); }
On the Android side, override the onBackPressed() method to give the Flutter side the event handling for the return key.
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); }
Finally, write a native MethodCallHandler callback that finish es the Activity directly if the current Flutter page is the first.
nativeChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() { @Override public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) { switch (methodCall.method) { case "goBack": // Return to the previous page finish(); break; default: result.notImplemented(); break; }
Reference address:
Flutter 49: Illustrate Flutter's native interaction with Android;
Flutter Learning Subtotal: Android Native Project introduces Flutter;