in Androidhtml
in Flutterjava
在Flutter中要实现一个应用的多个界面而且在界面间切换跳转须要用到两个核心的概念:android
1.Route: Route是应用中一个界面的抽象,相似Android中的Activity。app
2.Navigator: Navigator是一个Widget,它用于管理应用中全部的Route。一个Navigator能够经过push或者pop操做来入栈和出栈一个Route,进而实现从一个界面进入另外一个界面或者返回上一个界面的效果。less
与在Android中的AndroidManifest.xml中声明Activity相似,在Flutter中经过构造MaterialApp实例时传入的routes参数来配置Route。以下:异步
void main() {
runApp(new MaterialApp(
home: new MyAppHome(), // becomes the route named '/'
routes: <String, WidgetBuilder> {
'/a': (BuildContext context) => new MyPage(title: 'page A'),
'/b': (BuildContext context) => new MyPage(title: 'page B'),
'/c': (BuildContext context) => new MyPage(title: 'page C'),
},
));
}
复制代码
构造MaterialApp时与以前不一样的是咱们传入了一个Map做为其routes参数,该Map的key是String类型,value是一个用于构造对应Route的方法。 接下来就能够经过获取一个Navigator对象来改变当前屏幕内显示的Route:async
Navigator.of(context).pushNamed('/b');
复制代码
pushNamed方法传入的参数与以前在MaterialApp构造时配置的routes是匹配的,这个例子中将key为"/b"的Route入栈,进而界面跳转到Page B。ide
另外一个使用Intent主要的场景是去调用手机内的其余功能模块,好比启动相机或者文件管理器等。在这种状况下能够经过调用Android对应的平台接口来实现。后面的例子有简单用到Flutter中Android对应的平台接口。ui
小结: 在Flutter中处理界面间的跳转切换使用Navigator和Route配合完成。也能够经过Flutter提供的Android对应的平台接口去调用外部的其余模块。this
在Flutter中处理收到的Intent分为两个步骤: 1.接收Intent 这一步仍是利用Android的原理,在AndroidManifest.xml中配置咱们的Activity所可以接收的Intent。 2.处理数据 这一步经过Flutter提供的Android平台接口在Flutter层获取Android层接收到的Intent中所携带的数据内容。 经过一个例子来解释一下。 首先在AndroidManifest.xml中配置咱们的Activity能够接收的Intent种类:
<activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing until Flutter renders its first frame. It can be removed if there is no splash screen (such as the default splash screen defined in @style/LaunchTheme). -->
<meta-data android:name="io.flutter.app.android.SplashScreenUntilFirstFrame" android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
复制代码
这是一个AndroidManifest.xml配置文件片断,上面的配置说明咱们的应用能够接收Action为android.intent.action.SEND的Intent。
接着,在MainActivity中咱们实现接收Intent的逻辑,重点须要关注的是这里从Intent中获取的数据是如何传递给Flutter的:
package com.yourcompany.shared;
import android.content.Intent;
import android.os.Bundle;
import java.nio.ByteBuffer;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.ActivityLifecycleListener;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
String sharedText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
}
}
new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.contentEquals("getSharedText")) {
result.success(sharedText);
sharedText = null;
}
}
});
}
void handleSendText(Intent intent) {
sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
}
}
复制代码
MainActivity从FlutterActivity继承而来。这里主要是接收Action为android.intent.action.SEND的Intent,将该Intent中包含的数据提取出来保存在成员变量sharedText中。关键在于onCreate方法中构造了一个MethodChannel实例,构造时须要传递一个String参数做为标识,在后面Flutter层须要构造一样标识的MethodChannel。MethodChannel的做用主要就是为了实现Flutter层与Android层的通讯。关于MethodChannel的更多帮助信息能够参阅官方文档。
最后,在Flutter层咱们能够调用系统提供的接口请求Android层中保存的数据sharedText:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(new SampleApp());
}
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Sample Shared App Handler',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => new _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
static const platform = const MethodChannel('app.channel.shared.data');
String dataShared = "No data";
@override
void initState() {
super.initState();
getSharedText();
}
@override
Widget build(BuildContext context) {
return new Scaffold(body: new Center(child: new Text(dataShared)));
}
getSharedText() async {
var sharedData = await platform.invokeMethod("getSharedText");
if (sharedData != null) {
setState(() {
dataShared = sharedData;
});
}
}
}
复制代码
这段代码比较简单,展现一个咱们自定义的StatefulWidget在屏幕上,咱们主要关注与SampleAppPage对应的_SampleAppPageState类。首先这里使用与前面相同的标识构造了一个MethodChannel类,相同的标识才能保证这里的MethodChannel能与以前Android层中定义的MethodChannel通讯。另外定义了一个getSharedText异步方法,该方法中调用MethodChannel实例的invokeMethod方法,最终会回调到以前MainActivity中定义MethodChannel时传入的MethodCallHandler类的onMethodCall方法,该方法的methodCall参数封装Flutter层传递到Android层的信息,result参数用于向Flutter层返回结果信息。
小结: 接收Intent的配置和处理仍是在Android实现,不一样的是要在Flutter中处理接收到的Intent所带的数据时,须要使用MethodChannel类来完成Flutter层与Android层之间的通讯。
在Flutter中可使用Navigator类获取从当前Route返回到上一个Route时附带的数据信息。只须要对push返回的Future对象作一个await操做。关于Future,await,async不太清楚能够参阅官方文档,他们用来在Dart中实现异步同步功能。
好比咱们须要启动一个位置信息界面让用户选择他们所处的位置,咱们能够写下面的代码:
Map coordinates = await Navigator.of(context).pushNamed('/location');
复制代码
此处经过pushNamed方法将屏幕上的当前界面跳转到了一个位置信息界面(假设咱们已经配置好了/location对应的Route)。同时pushNamed会返回一个Future对象,咱们须要将该Future对象做为await的表达式。
而后在咱们的显示位置信息的界面中当用户选择好位置后咱们就经过pop当前的Route出栈来实现返回上一个界面的效果,并同时带上须要返回给上一个界面的数据信息:
Navigator.of(context).pop({"lat":43.821757,"long":-79.226392});
复制代码
pop的参数就是返回给上一个界面的数据信息,这里是一个Map类型的数据。表示位置信息的Route出栈后,上面的await表达式将被唤醒,而且接收到传递过来的Map数据。
小结: 在Flutter中使用Navigator向Route Stack中push一个Route时返回的是一个Future对象,经过await表达式能够实现等待界面返回的效果,而且Navigator从Route Stack中pop一个Route时能够带上参数,此时带的参数就会返回给唤醒的await表达式。进而实现相似startActivityForResult中的当前界面返回并传递参数给上一个界面的效果。