美文网首页
flutter 杂记

flutter 杂记

作者: jancywen | 来源:发表于2023-04-18 13:04 被阅读0次

    事件机制

    深入理解Flutter/Dart事件机制

    Flutter 从上到下分为框架层、引擎层和嵌入层三层

    Flutter的UI系统包含三棵树:Widget树、Element树、渲染树。
    他们的依赖关系是:Element树根据Widget树生成,而渲染树又依赖于Element树


    1655122296425.jpg

    Key的种类及用法

    flutter 中的key总的来说分为以下两种:

    • 局部键(LocalKey):ValueKey、ObjectKey、UniqueKey
    • 全局键(GlobalKey):GlobalObjectKey
    1. ValueKey
      ValueKey是通过某个具体的Value值来做区分的Key,ValueKey的值可以是任意类型,甚至可以是我们自定义的类的实例

    2. ObjectKey
      ObjectKey判断两个Key是否相同的依据是:两个对象是否具有相同的内存地址

    3. UniqueKey
      UniqueKey是一个唯一键,不需要参数,并且每一次刷新都会生成一个新的Key。

    4. GlobalKey && GlobalObjectKey
      GlobalKey是全局唯一的键,一般而言,GlobalKey有如下几种用途:

    用途1:获取配置、状态以及组件位置尺寸等信息

    final GlobalKey<_CounterState> _globalKey = GlobalKey();
    // 状态
    final _CounterState _counterState = _globalKey.currentState;
    // 配置
    final Counter counterWidget = _globalKey.currentWidget;
    // 位置尺寸
    RenderBox renderBox = _globalKey.currentContext.findRenderObject();
    

    (1)_globalKey.currentWidget:获取当前组件的配置信息(存在widget树中)
    (2)_globalKey.currentState:获取当前组件的状态信息(存在Element树中)
    (3)_globalKey.currentContext:获取当前组件的大小以及位置信息。

    用途2:实现控件的局部刷新

    插件实现原理

    我们知道一个完整的Flutter应用程序实际上包括原生代码和Flutter代码两部分。Flutter 中提供了平台通道(platform channel)用于Flutter和原生平台的通信,平台通道正是Flutter和原生之间通信的桥梁,它也是Flutter插件的底层基础设施。

    Flutter与原生之间的通信本质上是一个远程调用(RPC),通过消息传递实现:

    • 应用的Flutter部分通过平台通道(platform channel)将调用消息发送到宿主应用。
    • 宿主监听平台通道,并接收该消息。然后它会调用该平台的API,并将响应发送回Flutter。

    热重载

    Flutter 的热重载是基于 JIT 编译模式的代码增量同步。由于 JIT 属于动态编译,能够将 Dart 代码编译成生成中间代码,让 Dart VM 在运行时解释执行,因此可以通过动态更新中间代码实现增量同步。

    热重载的流程可以分为 5 步,包括:扫描工程改动、增量编译、推送更新、代码合并、Widget 重建。Flutter 在接收到代码变更后,并不会让 App 重新启动执行,而只会触发 Widget 树的重新绘制,因此可以保持改动前的状态,大大缩短了从代码修改到看到修改产生的变化之间所需要的时间。

    另一方面,由于涉及到状态的保存与恢复,涉及状态兼容与状态初始化的场景,热重载是无法支持的,如改动前后 Widget 状态无法兼容、全局变量与静态属性的更改、main 方法里的更改、initState 方法里的更改、枚举和泛型的更改等。

    Future

    Dart 内存管理 GC机制

    Dart的垃圾回收是分代的:年轻代和老年代

    • 1、调度
      GC与Flutter engine建立联系,当engine检测到应用程序处于空闲状态且没有用户交互时,它会发出通知。这样就使得GC有了收集的窗口从而不影响性能。

    • 2、年轻代
      这个阶段旨在清除寿命较短的短暂对象,例如stateless widgets。虽然它是阻塞的,但它比老年代mark-sweep快得多,并且当与调度结合使用时,几乎不会影响程序的运行。

    • 3、老年代(并行标记和并发扫描)
      当对象经历过一定次数的GC仍然存在,或者其生命周期较长(个人猜测类似于element和RenderObject这种需要多次复用,可变且创建比较耗费性能),将其放入老年代区域中。老年代采用标记整理的方法来回收对象。
      这种GC技术有两个阶段:首先遍历对象图,并标记仍在使用的对象。在第二阶段期间,扫描整个存储器,并且回收未标记的任何对象。然后清除所有标志。

    • 4、根据ioslate特性来优化
      dart中每个isolate都有自己的独立的堆栈内存空间,其各自的GC不会影响到其他isolate的。所以我们可以通过把部分占用内存空间较大且生命周期较短的对象方法其他isolate中,这样即使另外一个isolate GC了,并不会对我们显示UI的isolate造成影响。

    GetX

    1. 状态管理

    1. GetBuilder 手动刷新 消耗最少
    String address = '';
    
    GetBuilder<ShopDecorateController>(
      // init: ShopDecorateController(),
      id: 123,
      builder: (c) {
        return Text(c.address);
      }),
    
    1. GetX 响应式
    final name = ''.obs;
    
    GetX<ShopDecorateController>(
      // init: ShopDecorateController(),
      builder: (c) => Text(c.name))
    
    1. Obx 响应式
    final name = ''.obs;
    
    Obx(() => Text(controller.name))
    
    1. MixinBuilder 即可手动又可以响应
      final name = ''.obs;
      String address = '';
    
    MixinBuilder<ShopMixinController>(
          // init: ShopMixinController(),
          // id: '',
          builder: (c) {
            return Column(
              children: [
                Text(c.name.value),
                Text(c.address),
              ],
            );
          },
        )
    

    注意

    1. 监测不可嵌套
    2. GetWidget<Controller> + GetX<Controller>会生成多份 controller
    3. GetView<Controller> + Get.create() 同一界面多次跳转时会生成多个 controller,但controller 无法释放

    2. 路由管理

    MaterialApp --> GetMaterialApp
    // 普通导航
    Get.to(NextScreen());
    Get.back();
    
    /**
    * 别名路由导航
    */
    
    GetMaterialApp(
          getPages: [
            GetPage(name: '/next', page: () => NextScreen()),
    ]
    
    Get.toNamed('/next');
    

    3. 依赖管理

    4.GetView, GetWidget, GetService

    1. GetView
      它是一个对已注册的Controller有一个名为controller的getter的const Stateless的Widget,仅此而已。

    2. GetWidget
      "缓存 "了一个Controller, 使用Get.create(()=>Controller()) 会在每次调用时生成一个新的Controller

    3. GetService
      这个类就像一个 "GetxController",它共享相同的生命周期("onInit()"、"onReady()"、"onClose()")。 但里面没有 "逻辑"。它只是通知GetX的依赖注入系统,这个子类不能从内存中删除。

    关键字 extends, with, implements

    flutter 类相关关键字分析

    三种类结构可以同时存在,关键字的使用有前后顺序:extends -> mixins -> implements。
    另外需要注意的是相同方法的优先级问题,这个有两种情况:

    1. 同时被extends,with,implements时,混入(with)的优先级比继承(extends)要高,而implements只提供接口,不会被调用。
    2. with多个Mixin时,则会调用距离with关键字最远Mixin中的方法。

    当然,如果当前使用类重写了该方法,就会优先调用当前类中的方法。

    路由

    在Flutter中使用Route和Navigator来进行统一管理。Route是页面的抽象,主要负责创建界面、接收参数以及响应导航器Navigator的打开与关闭。而Navigator则用于维护路由栈管理

    • push():将给定的路由入栈,返回值是一个Future对象,用以接收路由出栈时的返回数据。
    • pop():将栈顶路由出栈,返回结果为页面关闭时返回给上一个页面的数据。
    • replace()、removeRoute()和popUntil()等

    Flutter中的路由管理可以分为基本路由和命名路由两种。

    • 基本路由:无需提前注册,在页面切换时需要手动构造页面的实例。
    • 命名路由:需要提前注册页面标识符,在页面切换时通过标识符直接打开新的路由。

    参考:
    Flutter异步编程-Future
    Flutter中的Key详解
    深入理解Flutter/Dart事件机制
    flutter 热重载
    Dart内存机制
    GetX使用---简洁的魅力!
    如何编写高质量前端代码
    Flutter架构
    Element、BuildContext和RenderObject
    【源码篇】Flutter GetX深度剖析 | 我们终将走出自己的路(万字图文)

    相关文章

      网友评论

          本文标题:flutter 杂记

          本文链接:https://www.haomeiwen.com/subject/ixxamrtx.html