上文介绍了原生跳转Flutter页面的基本方法,即
startActivity(
FlutterActivity.createDefaultIntent(currentActivity)
);
但是这样跳转只会跳转至Flutter的main入口处,现在介绍如何跳转至其他路由。
首先得在flutter模组中创建一个dart文件用来存储路由表,命名为routes.dart,文件代码如下
String homePage = "/";
String secondPage = "/secondPage";
final routes = {
homePage: (context) => const MyApp(),
secondPage: (context) => const DemoPage()
};
//下面这段代码是将一个匿名方法赋值给一个变量
//匿名方法做的事情:处理路由传参,生成 MaterialPageRoute 路由对象
var onGenerateRoute = (settings) {
Function? pageContentBuilder = routes[settings.name];
if (pageContentBuilder != null) {
if (settings.arguments != null) {
var route = MaterialPageRoute(
builder: (context) =>
pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
var route =
MaterialPageRoute(builder: (context) => pageContentBuilder(context));
return route;
}
}
};
然后修改main()函数如下
void main() => runApp(MaterialApp( //app 启动路由页面
initialRoute: homePage,
//路由生成
onGenerateRoute: onGenerateRoute,));
这里的初始入口仍然是flutter的初始页面,但是通过onGenerateRoute方法已经配置好了其他页面的路由,所以我们只需要在原生代码中传入指定页面的路由就能跳转了,以下是原生端的代码
startActivity(
FlutterActivity
.withNewEngine()
.initialRoute("/secondPage")
.build(currentActivity)//currentActivity替换为当前Activity
);
但是这样子有一个致命缺陷,从按下跳转键到完全跳转过去花费了大概五六秒的时间,这在实际开发中自然是不被允许的,因此有了FlutterEngine,先声明引擎
public FlutterEngine flutterEngine;
public void preWarm(){
flutterEngine = new FlutterEngine(this);
//设置初始化路由
flutterEngine.getNavigationChannel().setInitialRoute("/secondPage");
// 开始执行Dart模块预热引擎
flutterEngine.getDartExecutor().executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
);
// 缓存引擎
FlutterEngineCache
.getInstance()
.put("my_engine_id", flutterEngine);
}
然后在onCreate()方法中调用,就能达到提前预热的效果,这样在执行跳转时耗时会大大缩短。下面是跳转代码
startActivity(
FlutterActivity
.withCachedEngine("my_engine_id")
.build(SecondPage.this)
);
要注意的是,预热也是需要时间的,如果刚执行预热代码就马上跳转flutter页面,花费的时间与之前无异,但是缓存机制另一个好处就是第二次开始的跳转时间都会大幅缩短。而这样做的代价就是性能的消耗了,以下是官方文档原话:
当使用一个缓存的 FlutterEngine
时, FlutterEngine
会比展示它的 FlutterActivity
或 FlutterFragment
存活得更久。切记,Dart 代码会在你预热 FlutterEngine
时就开始执行,并且在你的 FlutterActivity
或 FlutterFragment
销毁后继续运行。要停止代码运行和清理相关资源,可以从 FlutterEngineCache
中获取你的 FlutterEngine
,然后使用 FlutterEngine.destroy()
来销毁 FlutterEngine
。
运行时的性能考量并不是你会预热和缓存一个 FlutterEngine
的唯一原因。一个预热的 FlutterEngine
会独立于 FlutterActivity
执行 Dart 代码,即一个 FlutterEngine
可以在任意时刻用于执行任意代码。非 UI 的应用逻辑可以在 FlutterEngine
中执行,例如网络请求和数据缓存,以及在 Service
中或其他地方的后台行为。当使用 FlutterEngine
在后台执行任务时,确保满足 Android 对于后台执行的所有限制。
并且,在原生和flutter之间进行跳转时,路由的变化是一个非常值得注意的点,举个例子,按照文中flutter路由表的定义方法来,原生界面是A,flutter界面有两个,分别是初始页面面B、第二个页面C,当我从A跳转至C时,B因为是main函数的初始页面,它其实也是被添加进了路由表的,这就导致了一个问题,当我在C页面调用flutter的Navigator.pop时,回到的页面不是A而是B,而在B调用pop方法则会直接黑屏,因为pop是flutter的路由方法,不能用它回到原生页面中,除非是使用手机自带的返回功能。并且,用这种方法回到了A界面后,再次调用同一个引擎跳转flutter界面时,即便你之前配置的初始化路由是C页面,此时跳转的界面仍然是B,因为缓存的引擎并没有被释放,它仍然停留在最后一次展示的flutter界面即B,故而再次调用时初始页面是B而不是C。原因是因为”/”,这里附上国外网友的回答:
Here is extract from the documentation:
If the route name starts with a slash, then it is treated as a “deep link”, and before this route is pushed, the routes leading to this one are pushed also. Even if the route was just /a, the app would start with / and /a loaded. api.flutter.dev/flutter/mat…
You could try re-naming your ‘/settings’ route to ‘settings’.
简单翻译一下就是,当你的路由表里使用了”/”时,flutter是把它当作深链接来处理的,即指向这个页面的页面也会被添加进路由表,这就是为什么我们只添加了C页面路由里却有B的原因,解决办法也很简单,在路由表里把”/secondPage”改成”secondPage”就行了。
但是还有一个问题没解决,即便flutter的路由表里只有一个页面了,调用Navigator.pop仍然无法回到原生页面,这时候就需要用到系统层级的返回方法了,即SystemNavigator.pop()。
这篇文章就记录到这里了,下一篇文章就记录原生和flutter的通讯交互了。