Flutter框架对热重载在项目里的深度运用,状态热重新加载以及静态字段被延迟初始化【Flutter】

时间:2022-12-24 07:15:14

热重载

要热重新加载Flutter应用程序: 从受支持的IntelliJ IDE或终端窗口运行应用程序。物理机和虚拟机都可以运行。 修改项目中的Dart文件。大多数类型的代码更改都可以重新加载;

class myWidget extends StatelessWidget {
  Widget build(BuildContext context) {
    return new GestureDetector(onTap: () => print('T'));
  }
}

Flutter的热重新加载功能可以帮助快速轻松地测试、构建用户界面、添加功能和修复错误,而无需重新启动应用程序。热重新加载是通过将更新的源代码文件注入正在运行的Dart虚拟机(VM)来实现的。在虚拟机用新的字段和函数更新类之后,Flutter框架将自动重建小部件树,以便可以快速查看更改的效果。

Performing hot reload...
Reloaded 1 of 448 libraries in 2,777ms.

如果使用IntelliJ IDE,请选择“全部保存”(cmd-s/ctrl-s),或单击工具栏上的“热重新加载”按钮。 如果使用命令行flutter run运行应用程序,请在终端窗口中输入r 成功热重新加载后,将在控制台中看到类似以下内容的消息。

class myWidget extends StatefulWidget {
  @override
  State createState() => new myWidgetState();
}
class myWidgetState {
...
...
}

状态热重新加载

Flutter的热重新加载功能(有时称为有状态热重新加载)保留了应用程序的状态。此设计允许仅查看最近更改的效果,而不放弃当前状态。例如,如果应用程序需要用户登录,则可以在导航层次结构中修改并重新加载页面,而无需重新输入登录凭据。状态保持不变,这通常是所需的行为。

myWidget is not a subtype of StatelessWidget

如果代码更改影响应用程序的状态(或其依赖关系),则应用程序必须使用的数据可能与从头开始执行的数据不完全一致。在热过载和完全重新启动后,结果可能是不同的行为。例如,如果将StatelessWidget类更改为StatefulWidget(反之亦然),则热重新加载后应用程序的先前状态将保持不变。但是,此状态可能与新更改不兼容。

静态字段被延迟初始化

运行应用程序后,如果进行以下更改:

final sampleTable = [
  new Table("T1"),
  new Table("T2"),
  new Table("T3"),
  new Table("T4"),
];

在Dart中,静态字段被延迟初始化。这意味着第一次运行Flutter应用程序并读取静态字段时,其初始值将设置为初始表达式的结果。全局变量和静态字段被视为状态,因此在热重新加载期间不会重新初始化。 如果更改全局变量和静态字段的初始化器,则需要完全重新启动以查看更改。

const foo = 1;
final bar = foo;
void onClick(){
  print(foo);
  print(bar);
}

然后热重新加载,现在打印2和1。对常量字段值的更改始终会重新加载,但静态字段初始值设定项语句不会重新运行(初始值可能是表达式的值)。从概念上讲,常量字段被视为别名而不是状态。

final bar = foo;

当一组更改需要完全重新启动才能生效时,Dart VM将检测初始化程序更改并标记。以上示例中的大多数初始化工作都会触发标记机制,但不适用于以下情况:

const bar = foo;

即使热重新加载操作看似成功且未引发异常,但某些代码更改可能在刷新的UI中不可见。更改应用程序的main()方法后,这种行为很常见。

作为一般规则,如果修改的代码位于根小部件的构建方法的下游,则热重载将按预期运行。但是,如果由于重新构建小部件树,修改后的代码不会被重新执行,那么在热重新加载后,将看不到其效果。都

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: () => print('tapped'));
  }
}

在完全重新启动后,程序从头开始执行main()的新版本,并构建一个小部件树以显示文本“Hello”。 但是,如果在更改后重新加载应用程序,main()将不会被重新执行,未修改的实例MyApp将被用作新构建的小部件树的根。热重新加载后,结果不会改变。

  class Color {
    Color(this.i, this.j);
    final Int i;
    final Int j;
  	}