代码
void main(List<String> args) {
// 1-runApp: Flutter 框架提供的全局函数。参数必须是一个 Widget。
//它会把这个 Widget 挂载到 Flutter 的根部 UI 树,并启动整个应用的渲染流程。
// 2-const MyApp(): 创建一个MyApp的实例
runApp(const MyApp());
}
const img1 = "https://linresource.uk/img/13399635147767705.jpg";
const img2 = "https://linresource.uk/img/13399635169004637.jpg";
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Center(child: const Text('有无状态组件'))),
body: Center(child: const BannerWidget()),
),
debugShowCheckedModeBanner: false,
);
}
}
class BannerWidget extends StatelessWidget {
const BannerWidget({super.key});
@override
Widget build(BuildContext context) {
return Image.network(img1);
}
}

执行流程(简化时序)
main()
↓
runApp(const MyApp())
↓
Flutter 创建 MyApp → 调用 MyApp.build()
↓
MyApp.build() 返回 MaterialApp(内部包裹 Scaffold)
↓
Scaffold.body 里创建 BannerWidget → 调用 BannerWidget.build()
↓
BannerWidget.build() 返回 Image.network(img1)
↓
Flutter 渲染引擎根据 Widget 树绘制 UI
↓
异步加载网络图片 → 加载完成后触发局部重绘
程序入口
void main(List<String> args) {
runApp(const MyApp());
}
Dart 程序入口:执行 main()
函数(所有 Dart 程序都从 main
开始)。
args
:命令行参数(一般 Flutter 移动端不会用到)。
runApp()
:
- Flutter 框架提供的全局函数。
- 参数必须是一个
Widget
(你传入的是const MyApp()
)。 - 它会把这个 Widget 挂载到 Flutter 的根部 UI 树,并启动整个应用的渲染流程。
const MyApp()
:调用 MyApp
这个类的常量构造函数(StatelessWidget 支持 const)。
常量构造函数
构造函数声明为 const
class MyApp extends StatelessWidget {
const MyApp({super.key});
}
这样声明表示:
- 如果构造参数(
{super.key}
)全是编译期常量,Dart 编译器可以在编译阶段就创建对象(而不是运行时)。 - 这个对象会被当作不可变值重用(节省内存、提升性能)。
为什么不可以变值可以提升性能
内存可重用(减少创建开销)
假设你写了:
const MyApp();
const MyApp();
Dart 编译器会在编译期就直接生成一个唯一的 MyApp
实例,并且两个地方都指向同一块内存地址。
这样:
- 少创建对象 → 减少内存分配和垃圾回收压力。
- 不需要复制数据 → 节省 CPU 时间。
而可变对象(mutable)可能会在运行时被修改,所以每次用都得创建一个新的,不能重用。
Flutter 可以跳过 UI 重建
Flutter 构建 UI 时,会比较新旧 Widget 树:
- 如果发现是同一个对象(内存地址相同),且是不可变的,就直接跳过 build 过程。
- 如果是新对象(哪怕内容一样),Flutter 也会认为它变了,触发重建。
// 不可变且 const
runApp(const MyWidget(title: 'Hello'));
// 每次重建都会用同一个对象
// 每次都是新对象
runApp(MyWidget(title: 'Hello'));
在 UI 一样的情况下,第一种跳过了大量不必要的 widget build,所以性能更好。
调用时的情况
如果类的构造函数声明成 const
,在调用的时候你可以用 const
关键字,但不是必须用。
带 const
(推荐)
runApp(const MyApp());
好处:
- 编译器会直接重用这个对象实例,而不是每次运行时重新创建。
- 在 widget 树中,如果
const
对象没变,Flutter 会跳过重建,提高渲染效率。
不带 const
runApp(MyApp());
效果上 UI 是一样的,但:
- 每次都会在运行时创建一个新的实例。
- 对于 Flutter 的 Widget Diff(比较新旧 Widget 树) 来说,这会被当作“新对象”,可能会触发不必要的重建。
MyApp
类(无状态组件)
代码说明
class MyApp extends StatelessWidget {
const MyApp({super.key});
- 继承 StatelessWidget → 说明这是一个无状态组件,数据不可变,UI 只能依赖构造函数参数。
super.key
:把 key 传给父类,用于 Flutter 的 widget 树比对优化(Widget Diff 算法)。
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Center(child: const Text('有无状态组件'))),
body: Center(child: const BannerWidget()),
),
debugShowCheckedModeBanner: false,
);
}
build()
方法:StatelessWidget 必须实现的抽象方法。
MaterialApp
:
- Flutter 提供的应用顶层容器(包含主题、路由、国际化等)。
home
属性:应用启动后显示的第一个页面。
Scaffold
:
- 提供页面结构(AppBar、Body、FloatingActionButton等)。
AppBar
:
- 应用顶部栏。
title
属性是一个 Widget,这里用Center
+Text
让标题居中。
body
:
- 页面主要内容区,这里用
Center
居中一个BannerWidget
。
BannerWidget
类(无状态组件)
class BannerWidget extends StatelessWidget {
const BannerWidget({super.key});
依然是无状态组件,没有持久化数据。
用
const
构造函数可减少重复创建 widget 的开销。
@override
Widget build(BuildContext context) {
return Image.network(img1);
}
build()
返回一个网络图片组件。Image.network(img1)
:通过 URL 加载网络图片。
运行时 Flutter 会先显示空白或占位,等网络请求完成后再绘制图片。
图片加载是异步的,但
build()
是同步执行的(UI 先返回结构,渲染引擎异步填充图片内容)。
关于build()
哪些类需要实现 build()
只有 Widget 才需要实现 build()
在 Flutter 中,不是所有类都要有
build()
方法。只有继承了
StatelessWidget
或StatefulWidget
(以及它们的父类Widget
)的类,才会要求你实现build()
方法。Widget
是一个抽象类,他还有其他许多子类- 这两个类是构建自定义 UI 的主要入口。其它 Widget 类型更多是作为框架内部或特殊场景使用,你在做业务 UI 时很少直接继承它们。
build()
是 Flutter 框架在构建 Widget 树时调用的,用来描述 UI 长什么样。用一个简单的例子:
void main() { runApp(const MyApp()); // 入口 } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const Text('Hello'); } }
执行过程大概是:
runApp(MyApp())
→ Flutter 框架接管程序。- 框架会把
MyApp
当成根 widget,交给 Flutter 渲染系统。 - 框架调用
MyApp.build(context)
→ 得到一个Text
widget。 - Flutter 根据这个 widget 构建 Element 树 和 RenderObject 树,最终在屏幕绘制 UI。
总结:
- Flutter 里“作为启动调用的类”如果是一个 Widget,就必须实现
build()
方法, - 框架会在需要构建 UI 时自动调用它,不需要你手动去调。
- Flutter 里“作为启动调用的类”如果是一个 Widget,就必须实现
什么时候调用build()
const MyApp()
和 const BannerWidget()
这两个地方虽然都是 创建 Widget 的子类实例,但它们不会在构造时立即调用 build()
方法。
这里只是调用构造函数,得到一个 Widget 实例(纯数据对象),它还没有被挂载到 Widget 树上,所以不会立刻执行 build()
。
Flutter 中 Widget 是“描述”
- 你写的
StatelessWidget
/StatefulWidget
只是一个UI 描述对象,并不是真正的 UI 元素。 - Flutter 的渲染引擎会拿到这个描述,然后创建对应的 Element 和 RenderObject 去真正绘制界面。
build()
方法就是在 Element 阶段调用的,用来生成下一层 Widget 树。
build()
的调用流程是:
runApp()
接收一个根 Widget(这里是MyApp
)。- Flutter 框架创建一个 Element(StatelessElement 或 StatefulElement)。
- Element 调用 Widget 的
build()
来生成子 Widget。 - 再递归生成所有子 Widget 的 Element 并 build。