简介
启动时间包含进程创建、Flutter 引擎和 Dart 执行、应用初始化以及首帧绘制等阶段。优化之前先定义测量起点、终点和构建模式;不同设备、系统和冷/温启动状态不能直接横向比较。
1. 不要在 build 中创建 Future
FutureBuilder 的 future 应在 initState、didUpdateWidget 等生命周期阶段获得。如果每次 build 都调用初始化方法,父组件重建时就可能重复启动数据库、配置或网络任务。
下面的 StartupGate 在 initState 中只创建一次 Future,并显示 loading、home 或 error。把业务初始化函数作为参数传入:
import 'package:flutter/material.dart';
class StartupGate extends StatefulWidget {
const StartupGate({
super.key,
required this.initialize,
required this.loading,
required this.home,
});
final Future<void> Function() initialize;
final Widget loading;
final Widget home;
@override
State<StartupGate> createState() => _StartupGateState();
}
class _StartupGateState extends State<StartupGate> {
late Future<void> _initialization;
@override
void initState() {
super.initState();
_initialization = widget.initialize();
}
@override
void didUpdateWidget(covariant StartupGate oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.initialize != widget.initialize) {
_initialization = widget.initialize();
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder<void>(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('启动失败:${snapshot.error}'));
}
if (snapshot.connectionState != ConnectionState.done) {
return widget.loading;
}
return widget.home;
},
);
}
}
在应用入口把当前项目的初始化函数和页面传入 StartupGate。初始化函数只应等待首屏确实依赖的工作;可延迟的同步、网络请求和预热应在首屏后安排,并提供失败处理。
如果使用 FutureBuilder 加载多个彼此独立的任务,可以用 Future.wait 并行等待;有依赖关系的初始化步骤仍要按依赖顺序执行。不要用假定的单项耗时相加来承诺优化结果。
2. 区分首帧之前与首帧之后
首帧前的工作应保持精简。Flutter 页面中的 Splash widget 只能在 Dart 首帧开始后绘制;它不能替代 Android / iOS 提供的原生启动画面。
一个常见拆分方式:
- 首屏路由必须的数据:等待并显示应用内 loading 状态。
- 非关键接口、埋点或非首屏资源:页面可交互后按需加载。
- 大文件解析或 CPU 密集计算:先测量,再考虑 isolate 或延迟处理。
- 插件初始化:按插件依赖、平台要求和失败影响决定,不要只凭“延迟初始化更快”机械移动。
3. 记录可比较的启动基线
每次测量应记录设备型号、系统版本、Flutter commit、release/profile 模式、冷启动或温启动定义、起止事件和重复次数。用相同场景比较分位数,而不是仅凭单次 Stopwatch 结果。
Flutter DevTools Performance 和平台启动分析工具可以帮助定位阶段;日志本身也会带来开销,不要把 debug 模式的数据当作 release 结论。
实战记录
我在物流项目中把 Global.init 的工作收缩到设置系统 UI 和读取首页跳转所需的本地 token。网络请求和非首屏预加载移到首页后执行。这是项目中的拆分经验;当时没有保留设备、构建模式和前后启动数据,因此本文不声称有量化提速结果。
