Flutter混合开发实战(二)引擎预热和缓存

上文介绍了原生跳转Flutter页面的基本方法,即

scss 复制代码
 startActivity(
      FlutterActivity.createDefaultIntent(currentActivity)
    );

但是这样跳转只会跳转至Flutter的main入口处,现在介绍如何跳转至其他路由。

首先得在flutter模组中创建一个dart文件用来存储路由表,命名为routes.dart,文件代码如下

ini 复制代码
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()函数如下

less 复制代码
void main() => runApp(MaterialApp(   //app 启动路由页面
  initialRoute: homePage,
  //路由生成
  onGenerateRoute: onGenerateRoute,));

这里的初始入口仍然是flutter的初始页面,但是通过onGenerateRoute方法已经配置好了其他页面的路由,所以我们只需要在原生代码中传入指定页面的路由就能跳转了,以下是原生端的代码

less 复制代码
startActivity(
        FlutterActivity
                .withNewEngine()
                .initialRoute("/secondPage")
                .build(currentActivity)//currentActivity替换为当前Activity
);

但是这样子有一个致命缺陷,从按下跳转键到完全跳转过去花费了大概五六秒的时间,这在实际开发中自然是不被允许的,因此有了FlutterEngine,先声明引擎

scss 复制代码
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()方法中调用,就能达到提前预热的效果,这样在执行跳转时耗时会大大缩短。下面是跳转代码

kotlin 复制代码
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的通讯交互了。

相关推荐
Easyhood31 分钟前
Android 开发入门实践(十四):Compose 副作用入门与四个常用 API
android·开发语言·kotlin·android jetpack·compose
FlightYe2 小时前
音视频修炼之容器与协议(四):RTSP详解
android·linux·ffmpeg·音视频·dash
疯华整猫3 小时前
删掉 LeakCanary 那天,我用 Trae 自己撸了一套:最难的不是分析堆,是决定什么时候 dump
android·人工智能·性能优化
mmsx11 小时前
耳切法切带洞多边形:论文能跑通,真实数据为什么崩
android·kotlin
洞见前行11 小时前
你的 Activity 关了,为什么还活着?Android 内存泄漏从发现、定位到线上治理
android·性能优化·leakcanary
Kapaseker13 小时前
Kotlin 又要加语法糖了:这次轮到 if-else
android·kotlin
恋猫de小郭15 小时前
Flutter 3.50 & Dart 3.14 发布,快来看看有什么更新吧
android·前端·flutter
喵个咪1 天前
GoWind CMS 拆解:Flutter 设计系统内核——双态 token、四档断点与自适应壳层
前端·flutter·交互设计