FSA全栈行动 FSA全栈行动
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr

公众号:FSA全栈行动

记录学习过程中的知识
首页
  • 移动端文章

    • Android
    • iOS
    • Flutter
  • 学习笔记

    • 《Kotlin快速入门进阶》笔记
    • 《Flutter从入门到实战》笔记
    • 《Flutter复习》笔记
前端
后端
  • 学习笔记

    • 《深入浅出设计模式Java版》笔记
  • 逆向
  • 分类
  • 标签
  • 归档
  • LinXunFeng
  • GitLqr
  • AndroidUI

  • Android第三方SDK

  • Android混淆

  • Android仓库

  • Android新闻

  • Android系统开发

  • Android源码

  • Android注解AOP

  • Android脚本

  • AndroidTv开发

  • AndroidNDK

  • Android音视频

  • Android热修复

  • Android性能优化

  • Android云游戏

  • Android插件化

  • iOSUI

  • iOS工具

  • iOS底层原理与应用

  • iOS组件化

  • iOS音视频

  • iOS疑难杂症

  • iOS之Swift

  • iOS之RxSwift

  • iOS开源项目

  • iOS逆向

  • Flutter开发

    • Dart - 抽象类的实例化
    • Flutter - 打印好用的Debug日志
    • Flutter - 混合开发
    • Flutter - 解决混合开发iOS脚本打包遇到的问题
    • Flutter - 低版本在iOS14上遇到的问题与解决方案
    • Flutter - 解决原生弹窗的触摸事件被Flutter响应的问题
    • Flutter - 实现列表上下拉切换header
    • Flutter - 获取ListView当前正在显示的Widget信息
    • Flutter - 列表滚动定位超强辅助库,墙裂推荐!🔥
    • Flutter - 快速实现聊天会话列表的效果,完美💯
    • Flutter - 聊天输入框更新文本时的必备优化点🔖
    • Flutter - 我给官方提PR,解决run命令卡住问题 😃
    • Flutter - 探索run命令到底做了什么 🤔
    • Flutter - 引擎调试(iOS篇)🛠
    • Flutter - 引擎调试bug到提交PR实战 🐞
    • Flutter - 船新升级😱支持观察第三方构建的滚动视图💪
    • Flutter - 瀑布流交替播放视频 🎞
    • Flutter - IM保持消息位置大升级(支持ChatGPT生成式消息) 🤖
    • Flutter - 滚动视图中的表单防遮挡 🗒
    • Flutter - 秒杀1/2曝光统计 📊
    • 一天内加入 Flutter 和 FlutterCandies 两大组织是什么体验 🧐
    • Flutter - 如何快速搓一个微信通讯录列表(azlist) 📓
    • Flutter - 混编项目集成Shorebird热更新🐦(安卓篇)
    • Flutter - 混编项目集成Shorebird热更新🐦(iOS篇)
    • Flutter - 解决返回原生页面时dispose方法未被触发的问题 🐞
    • Flutter - 升级3.19之后页面多次rebuild?🤨
    • Flutter - 热更新 Shorebird 1.0 正式版来了 🐦
    • Flutter - 使用Pigeon实现视频缓存插件 🐌
    • Flutter - 轻松搞定屏幕旋转功能 😎
    • Flutter - 解决Connection closed before full header was received
    • Flutter - 实现聊天键盘与功能面板的丝滑切换 🍻
    • Flutter - 支持观察NestedScrollView,兼容性更强 😈
    • Flutter - 聊天键盘与面板丝滑切换的强势升级 🍻
    • Flutter - 升级到3.24后页面还会多次rebuild吗?🧐
      • 一、问题回顾
      • 二、波折
      • 三、使用
      • 四、最后
    • Flutter - 轻松实现PageView卡片偏移效果
    • Flutter - 轻松搞定炫酷视差(Parallax)效果
    • Flutter - 危!3.24版本苹果审核被拒!
    • Flutter - 子部件任意位置观察滚动数据
    • Flutter - iOS编译加速
    • Flutter - Xcode16 还原编译速度
  • 移动端
  • Flutter开发
LinXunFeng
2024-08-11
目录

Flutter - 升级到3.24后页面还会多次rebuild吗?🧐

欢迎关注微信公众号:[FSA全栈行动 👋]

# 一、问题回顾

在今年 2月份,Flutter 官方正式了 3.19.0 版本,当时我们并没有着急尝鲜,直到 3月中旬,为了解决安卓端的崩溃率飙升问题,被迫无奈升级到 3.19.3, 结果踩了个坑,页面居然会多次 rebuild ~

在一番探索之后定位到根本原因,给官方提了 PR,以及跟大家分享了补丁来临时处理这个问题。探索的相关内容总结和补丁在《Flutter - 升级3.19之后页面多次rebuild?🤨 (opens new window)》中,有兴趣的小伙伴可以看看。

# 二、波折

不过当时(日期:3.19)所提 PR 并不被接受,因为其修改内容是直接给了个选项 createDependency,代码如下:

static ModalRoute<T>? of<T extends Object?>(
  BuildContext context, {
  bool createDependency = true,
}) {
  _ModalScopeStatus? widget;
  if (createDependency) {
    widget = context.dependOnInheritedWidgetOfExactType<_ModalScopeStatus>();
  } else {
    widget = context
        .getElementForInheritedWidgetOfExactType<_ModalScopeStatus>()
        ?.widget as _ModalScopeStatus?;
  }
  return widget?.route as ModalRoute<T>?;
}

如果将 createDependency 参数设置为 false,则不与 BuildContext 建立依赖关系,这被认定为是 footgun。

footgun: 指在尝试解决问题时,无意中导致更多问题或损害自己利益的行为

因为审核人担心如果允许了这个参数的加入,则后续可能会有开发者提出因为这个参数没有正确设置为 true,而导致在确实需要重新构建时却无法正常自动刷新视图的 bug 问题。最后建议提供类似 ModalRoute.argumentsOf(context) 的方式,进而尽量避免造成 rebuild。

这种方式的好处就跟 MediaQuery.of(context).viewInsets 对比 MediaQuery.viewInsetsOf(context) 一样,后者只会在 viewInsets 发生变化时才会 rebuild, 而前者只要是 MediaQueryData 的值(如: size)有变化就会 rebuild。

很好的提议 👍,不过我当时(日期:4.16)因为太忙,表明自己没时间去处理,并将 PR 关闭了,暂时靠补丁苟着。

当时有人提出另外一种较为安全的临时处理方案,就是遍历找出 _ModalScopeStatus,从而拿到 ModalRoute,以此来绕过绑定 BuildContext 的过程,相关代码如下。

/// replace ModalRoute.of(context)
class MyModalRoute {
  static ModalRoute<dynamic>? of(BuildContext context) {
    ModalRoute<dynamic>? route;
    context.visitAncestorElements((element) {
      if(element.widget.runtimeType.toString() == '_ModalScopeStatus') {
        dynamic widget = element.widget;
        route = widget.route as ModalRoute;
        return false;
      }
      return true;
    });
    return route;
  }
}

使用方式也很简单,只需要将原来的 ModalRoute.of(context) 替换为 MyModalRoute.of(context) 即可。

不过后面有人发现,在使用 代码混淆 功能时,该方案会失效。因为他是按字符串找到的 _ModalScopeStatus,但是在混淆的时候会重命名相关类名,所以还在 3.19.x 小伙伴们,请自行根据自身情况,考虑是否使用。

时间过的很快,转眼来到 5月份,一看这个问题还没有处理,于是抽了点时间按照建议,做了些调整,于 5.24 提交了 PR (https://github.com/flutter/flutter/pull/149022 (opens new window)) ,并在 5.30 完成合并。

# 三、使用

此 PR 的改动也终于随 Flutter 3.24.0 正式版发布了,新增了如下三个方法:

  • isCurrentOf: 对应 isCurrent,用于判断当前路由是否为栈顶路由。
  • canPopOf: 对应 canPop,用于判断当前路由是否可以弹出/关闭。
  • settingsOf: 对应 settings,当前路由的配置(路由名、参数)。

之前取路由参数的方式如下代码所示

final arguments = ModalRoute.of(context)?.settings.arguments;

需调整为

final arguments = ModalRoute.settingsOf(context)?.arguments;

对,这样就可以了,不调整的话还是会造成 rebuild 的 ~

# 四、最后

其实对于我个人而言,我还是比较钟意添加 createDependency 参数这种方式的,让开发者自由选择。

而且在做路由监听的时候依旧还是得用到 ModalRoute.of(context) ~

void main() {
  runApp(MyApp());
}

RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      navigatorObservers: [routeObserver],
      ...,
    );
  }
}

class _MyPageState extends State<MyPage> with RouteAware {
...
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    // 这里用到了 ModalRoute.of(context)
    routeObserver.subscribe(this, ModalRoute.of(context)!);
  }

  @override
  void dispose() {
    routeObserver.unsubscribe(this);

    super.dispose();
  }
  ...
}

好吧,本篇到此结束,感谢大家的支持,我们下次再见! 👋

#Dart#Flutter
Flutter - 聊天键盘与面板丝滑切换的强势升级 🍻
Flutter - 轻松实现PageView卡片偏移效果

← Flutter - 聊天键盘与面板丝滑切换的强势升级 🍻 Flutter - 轻松实现PageView卡片偏移效果→

最近更新
01
Flutter - Xcode16 还原编译速度
04-05
02
AI - 免费的 Cursor 平替方案
03-30
03
Android - 2025年安卓真的闭源了吗
03-28
更多文章>
Theme by Vdoing | Copyright © 2020-2025 FSA全栈行动
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×