【Flutter】Flutter 中有哪些耗时操作?从 UI 卡顿到 Isolate 性能优化
作者:ZFJ_张福杰
博客:https://zfj1128.blog.csdn.net
日期:2026-09-20
关键词:Flutter、性能优化、Isolate、耗时操作、卡顿、WebSocket、JSON解析
前言
在做 Flutter 项目时,我们经常会遇到一个问题:
🤔 明明代码看起来没什么问题,为什么页面还是会卡?
比如:
- WebSocket 行情一更新,列表就开始掉帧
- 接口返回大量 JSON,页面明显停顿一下
- K线切换周期时,UI 突然卡住
- 图片压缩时动画不动了
- 一个
for循环直接把页面卡死 Future明明已经异步了,为什么还是卡?
很多人第一反应是:
👉🏻 Flutter 性能不行?
其实大多数时候不是 Flutter 的问题,而是:
👉🏻 我们把耗时任务放到了 Main Isolate 上执行
在这里,我结合自己 Flutter 项目的实际开发经验,总结一下:
🤑 Flutter 中常见的耗时操作,以及这些操作到底应该怎么优化。
一、什么叫"耗时操作"?
首先要明确一点:
耗时 ≠ 一定卡 UI
比如:
dart
final response = await dio.get(url);
这个接口可能需要:
text
2 秒
但 UI 不一定会卡 2 秒。
因为这 2 秒大部分时间是在:
text
等待网络
CPU 并没有一直在执行 Dart 代码。
但是如果我们写:
dart
for (int i = 0; i < 100000000; i++) {
// 大量计算
}
情况就不一样了。
这时候 CPU 会一直执行:
text
计算
计算
计算
计算
...
如果它运行在 Main Isolate:
👉🏻 UI 就可能直接卡住。
所以我们真正需要关注的是:
长时间占用 Main Isolate 的任务
二、为什么耗时操作会造成 Flutter 卡顿?
Flutter 默认情况下,大部分 Dart 代码运行在:
dart
Main Isolate
Main Isolate 不只是跑我们的业务代码,它还需要处理:
dart
用户点击
动画
Widget Build
Layout
Paint
事件回调
业务逻辑
假设是一个 60Hz 的设备:
dart
1 秒 = 60 帧
每一帧留给我们的时间大约只有:
dart
1000 / 60 ≈ 16.67ms
理想情况下:
dart
业务代码
↓
Build
↓
Layout
↓
Paint
↓
16.67ms 内完成
如果某个任务突然执行:
dart
50ms
100ms
500ms
那么 UI 就没办法及时处理下一帧。
最终表现就是:
dart
掉帧
↓
卡顿
↓
动画不流畅
↓
点击无响应
所以 Flutter 性能优化有一个非常核心的原则:
👉🏻 不要让 Main Isolate 长时间执行复杂计算。
三、第一类:大量循环和数据计算
这是最典型的 CPU 耗时任务。
比如:
dart
int calculate() {
int result = 0;
for (int i = 0; i < 100000000; i++) {
result += i;
}
return result;
}
如果直接:
dart
final result = calculate();
那么 Main Isolate 必须等:
text
100000000 次循环执行完成
这期间 UI 很可能直接卡死。
常见场景
比如:
- 大 List 遍历
- 数学计算
- 数据统计
- 技术指标计算
- Hash 计算
- 加密算法
- 图片算法
- 数据过滤
- 数据聚合
例如交易所里面:
dart
for (final ticker in tickers) {
calculatePrice(ticker);
}
几十条问题不大。
但是如果变成:
dart
10000 条
并且:
dart
每 100ms 执行一次
就完全是另外一个问题了。
四、第二类:大 JSON 解析
这个应该是 Flutter 项目里非常常见的性能问题。
例如接口返回:
dart
5MB JSON
然后我们:
dart
final data = jsonDecode(response.data);
很多人觉得:
dart
jsonDecode()
只有一行代码,应该很快。
实际上:
👉🏻 JSON Decode 是 CPU 计算。
尤其后面通常还会继续:
dart
JSON String
↓
jsonDecode
↓
Map
↓
Model.fromJson
↓
List<Model>
比如:
dart
final list = (json['data'] as List)
.map((e) => UserModel.fromJson(e))
.toList();
假设接口返回:
dart
10000 条
那就意味着需要:
dart
解析 JSON
+
创建 10000 个 Map
+
创建 10000 个 Model
+
创建 List
这时候很容易出现:
dart
接口请求已经完成
但是页面还是卡一下
真正耗时的可能不是:
dart
HTTP
而是:
dart
JSON Decode + Model 转换
五、第三类:List 排序、过滤、转换
比如:
dart
list.sort(
(a, b) => b.price.compareTo(a.price),
);
如果:
dart
100 条数据
基本没什么问题。
但是:
dart
10000 条
50000 条
100000 条
情况就不一样了。
更常见的是这种:
dart
final result = list
.where((e) => e.isOpen)
.map((e) => convert(e))
.toList()
..sort(
(a, b) => b.price.compareTo(a.price),
);
看起来很舒服。
但实际上执行了:
dart
遍历
↓
过滤
↓
对象转换
↓
创建 List
↓
排序
如果这是普通页面偶尔执行一次,问题可能不大。
但如果放在:
dart
WebSocket 回调
里面:
dart
每秒执行几十次
性能问题马上就出来了。
六、第四类:O(n²) 数据查找
这个在实际项目里面非常容易出现。
比如:
dart
for (final ticker in tickers) {
final instrument = instruments.firstWhere(
(e) => e.symbolId == ticker.symbolId,
);
}
乍一看没问题。
但是假设:
dart
tickers = 2000
instruments = 2000
外面遍历:
dart
2000 次
里面最坏再查:
dart
2000 次
复杂度接近:
dart
O(n²)
也就是:
dart
2000 × 2000
= 4,000,000 次比较
如果行情每:
dart
100ms
来一次:
👉🏻 这就是非常明显的性能隐患。
怎么优化?
提前创建 Map:
dart
final instrumentMap = {
for (final item in instruments)
item.symbolId: item,
};
然后:
dart
for (final ticker in tickers) {
final instrument = instrumentMap[ticker.symbolId];
}
原来:
dart
O(n²)
优化后接近:
dart
O(n)
这种优化,在行情类 APP 中非常重要。
七、第五类:WebSocket 高频数据
交易所 APP 里面,这应该是最典型的问题之一。
比如同时订阅:
dart
Ticker
OrderBook
Trades
Position
Balance
Kline
Index Price
Mark Price
然后服务器疯狂推:
dart
WS
WS
WS
WS
WS
WS
每来一条数据,我们都执行:
dart
jsonDecode
↓
Model.fromJson
↓
List 查找
↓
数据更新
↓
排序
↓
notifyListeners
↓
Widget rebuild
单次可能只需要:
dart
2ms
看起来非常快。
但假设:
dart
每秒 100 次
那么:
dart
2ms × 100
= 200ms
所以高频场景中一个非常重要的概念就是:
👉🏻 单次不慢,不代表高频执行以后不慢。
我的处理方式
一般不会:
text
WS → UI
WS → UI
WS → UI
WS → UI
而是:
dart
WS
WS
WS
WS
WS
↓
Cache
↓
Throttle
↓
统一处理
↓
UI
例如:
dart
100ms
统一更新一次。
这样可以大幅降低:
dart
计算次数
Widget rebuild 次数
状态通知次数
八、第六类:图片处理
图片也是典型的耗时任务。
例如:
dart
拍照
↓
读取图片
↓
压缩
↓
裁剪
↓
缩放
↓
旋转
↓
Base64
↓
上传
这些操作里面:
dart
图片压缩
图片解码
图片 Resize
滤镜处理
Base64
都可能产生大量 CPU 和内存开销。
比如一张:
dart
4000 × 3000
的图片。
像素数量就是:
dart
12,000,000
如果解码成 RGBA:
dart
12,000,000 × 4 bytes
≈ 48MB
也就是说:
👉🏻 一张十几 MB 的 JPEG,解码到内存以后可能变成几十 MB。
所以图片问题通常不只是:
dart
CPU
还有:
dart
Memory
GC
九、第七类:加密、Hash 和区块链签名
如果是做:
dart
Web3
钱包
区块链
这一类操作就非常常见。
比如:
dart
AES
SHA256
Keccak256
PBKDF2
scrypt
Argon2
ECDSA
secp256k1
都是典型 CPU 计算。
例如钱包解锁流程:
dart
密码
↓
PBKDF2
↓
生成 Key
↓
AES 解密
↓
助记词
↓
派生私钥
↓
生成地址
如果这些全部放在 Main Isolate:
👉🏻 很容易造成页面卡顿。
特别是:
dart
PBKDF2
scrypt
Argon2
这类算法本身就会故意提高计算成本。
再比如:
dart
for (int i = 0; i < 1000; i++) {
deriveAddress(i);
}
一次生成:
text
1000 个 HD Wallet 地址
也非常适合放到后台 Isolate。
十、第八类:K线指标计算
交易所 APP 里面另外一个非常典型的场景:
dart
Kline
假设获取:
dart
5000 根 K线
同时计算:
text
MA
EMA
MACD
RSI
BOLL
KDJ
VOL
如果每次:
dart
切换周期
拖动图表
收到新 K 线
都把全部 5000 根重新算一次:
dart
5000 × N 个指标
性能肯定会受到影响。
更合理的方式
第一次:
dart
Raw Kline
↓
计算指标
↓
缓存
↓
UI
收到最新 Kline 时:
dart
Last Kline
↓
只增量计算最后一点
而不是:
dart
新来一根 Kline
↓
全部 5000 根重新计算
这种思想其实不仅适用于 K线。
任何实时数据都应该优先考虑:
👉🏻 增量更新,而不是全量重算。
十一、第九类:OrderBook 深度计算
例如:
dart
asks
bids
服务器不停推深度变化。
最简单的实现可能是:
dart
asks.clear();
asks.addAll(newAsks);
asks.sort(...);
bids.clear();
bids.addAll(newBids);
bids.sort(...);
如果:
dart
每 50ms
执行一次:
dart
clear
addAll
sort
clear
addAll
sort
很容易造成 CPU 压力。
更合理的设计:
dart
Snapshot
+
Incremental Update
+
Cache
+
Batch
+
Throttle UI
也就是说:
👉🏻 服务端推哪一档发生变化,我们就更新哪一档。
而不是:
👉🏻 每次都重新处理全部深度。
十二、第十类:大量 Widget Rebuild
Flutter 性能问题不只有 CPU 计算。
还有:
text
UI Build
比如:
dart
setState(() {});
如果放在一个非常大的页面:
dart
ContractPage
├─ Header
├─ Kline
├─ OrderBook
├─ OrderForm
├─ Positions
├─ Orders
└─ BottomNavigation
一个价格发生变化:
dart
BTC Price
结果:
dart
整个页面重新 Build
明显没必要。
特别是行情:
dart
每 100ms 更新一次
如果整个交易页面每 100ms rebuild:
👉🏻 性能压力会非常大。
正确思想
把页面拆小:
dart
ContractPage
├ PriceWidget
├ KlineWidget
├ OrderBookWidget
├ PositionWidget
└ OrderWidget
价格更新:
dart
只刷新 PriceWidget
仓位更新:
dart
只刷新 PositionWidget
核心原则:
👉🏻 谁的数据变化,就尽量只刷新谁。
十三、第十一类:大 ListView
比如:
dart
Column(
children: list.map(
(e) => OrderItem(e),
).toList(),
);
如果:
dart
5000 条
意味着:
👉🏻 一次创建 5000 个 Widget。
这种写法肯定不适合长列表。
应该:
dart
ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return OrderItem(
list[index],
);
},
);
因为:
dart
ListView.builder
会按需构建当前屏幕附近的 Widget。
同理:
dart
GridView.builder
SliverList
SliverGrid
都属于这种思路。
十四、第十二类:文件 IO
例如:
dart
final bytes = File(path).readAsBytesSync();
这里有一个非常重要的关键词:
dart
Sync
也就是:
dart
同步
同步 IO 会等待文件读取完成以后才继续执行。
所以尽量不要在 UI 路径中:
dart
readAsBytesSync();
readAsStringSync();
writeAsBytesSync();
而应该:
dart
final bytes = await File(path).readAsBytes();
常见耗时文件操作:
text
读取大文件
写大文件
遍历目录
ZIP 解压
ZIP 压缩
日志扫描
缓存扫描
视频文件处理
十五、第十三类:数据库大量读写
例如:
dart
for (final item in list) {
await box.put(
item.id,
item,
);
}
如果:
dart
10000 条
就可能执行:
dart
10000 次写入
更合理的是:
dart
await box.putAll(data);
常见数据库性能问题:
dart
循环 Insert
循环 Update
循环 Delete
全表扫描
没有 Index
一次加载全部数据
复杂 Query
优化方向一般是:
dart
Batch
Index
Pagination
Transaction
Cache
十六、第十四类:大量临时对象和 GC
有些项目 CPU 看起来不高,但页面仍然偶尔卡一下。
这个时候还需要考虑:
dart
GC
比如:
dart
final newList = List.from(oldList);
行情每:
dart
50ms
执行一次。
假设 List:
dart
5000 条
那么一秒可能创建:
dart
20 个临时 List
再加上:
dart
Model
Map
String
Iterable
List
大量临时对象最终都会等待:
dart
Garbage Collection
整个流程:
dart
疯狂创建对象
↓
Heap 增长
↓
GC
↓
回收对象
↓
继续创建
所以实时行情优化还需要考虑:
👉🏻 减少不必要的对象创建。
十七、Future 为什么解决不了 CPU 卡顿?
这是 Flutter 很多人容易误解的地方。
比如:
dart
Future(() {
for (int i = 0; i < 100000000; i++) {
// calculate
}
});
很多人的理解是:
dart
Future
=
后台线程
实际上不是。
Future 主要解决的是:
dart
异步调度
并不意味着:
dart
一定创建新的 Isolate
如果这段 CPU 任务最终还是在 Main Isolate 执行:
👉🏻 一样会卡。
所以:
dart
Future
async
await
解决的是:
等待问题
而:
dart
Isolate
compute
解决的是:
CPU 阻塞问题
这是 Flutter 性能优化里面必须理解的区别。
十八、那什么时候应该使用 Isolate?
我的判断方式非常简单:
第一种:IO Bound
也就是:
dart
主要时间在等待
例如:
dart
HTTP
Socket
WebSocket
File IO
Database IO
通常优先:
dart
async / await
第二种:CPU Bound
也就是:
text
CPU 一直在算
例如:
dart
JSON Decode
大量排序
大量遍历
加密
Hash
图片处理
压缩
K线指标
复杂算法
这种情况就要考虑:
dart
Isolate
十九、使用 Isolate.run
现在比较简单的方式:
dart
final result = await Isolate.run(() {
return calculateData(data);
});
比如 JSON:
dart
Future<List<UserModel>> parseUsers(
String jsonString,
) async {
return Isolate.run(() {
final json = jsonDecode(jsonString) as List;
return json
.map(
(e) => UserModel.fromJson(e),
)
.toList();
});
}
执行流程:
dart
Main Isolate
│
├──── Data ────► Worker Isolate
│
│ ↓
│ jsonDecode
│ ↓
│ Model
│ ↓
◄──── Result ───────┘
│
↓
UI
这样复杂计算就不会一直堵塞 Main Isolate。
二十、使用 compute
Flutter 里面也可以:
dart
final result = await compute(
parseUsers,
jsonString,
);
例如:
dart
List<UserModel> parseUsers(
String jsonString,
) {
final json = jsonDecode(jsonString) as List;
return json
.map(
(e) => UserModel.fromJson(e),
)
.toList();
}
调用:
dart
final users = await compute(
parseUsers,
jsonString,
);
对于:
dart
JSON
数据转换
算法计算
这种一次性任务非常方便。
二十一、是不是所有东西都应该扔到 Isolate?
当然不是。
这是另外一个非常常见的误区:
dart
耗时?
↓
全部 Isolate
其实 Isolate 本身也有成本。
例如:
dart
创建 Isolate
数据传输
对象拷贝
结果返回
销毁 Isolate
如果一个任务只有:
dart
0.2ms
为了它创建 Isolate:
👉🏻 很可能得不偿失。
所以真正应该优化的是:
已经对 UI 帧产生明显影响的计算。
对于高频计算:
dart
每 50ms
每 100ms
如果不断:
dart
创建 Isolate
销毁 Isolate
也不一定合理。
这种情况下可以考虑:
dart
Long-running Isolate
也就是:
dart
Worker Isolate
长期存在:
dart
Main
│
├─ data ─► Worker
│
◄─ result ─ Worker
│
├─ data ─► Worker
│
◄─ result ─ Worker
而不是:
dart
创建
执行
销毁
创建
执行
销毁
创建
执行
销毁
二十二、Flutter 项目里我重点关注哪些耗时操作?
如果让我在实际项目中排查,我一般会重点关注下面这些:
| 场景 | 问题类型 | 优化方式 |
|---|---|---|
| 网络请求 | IO | async / await |
| WebSocket | 高频 IO | Cache + Throttle |
| JSON Decode | CPU | Isolate |
| Model 转换 | CPU | Isolate / 减少创建 |
| List 排序 | CPU | 减少排序 / Isolate |
| 大量遍历 | CPU | 优化算法 |
| List 查找 | CPU | Map / Set |
| 图片压缩 | CPU | Isolate / Native |
| 图片解码 | CPU + Memory | Resize / Cache |
| AES / Hash | CPU | Isolate |
| 钱包签名 | CPU | Isolate |
| K线指标 | CPU | Isolate + 增量计算 |
| OrderBook | 高频 CPU | 增量更新 |
| 文件读写 | IO | Async |
| 数据库 | IO | Batch / Index |
| 大列表 | UI | ListView.builder |
| 高频 setState | UI | 局部刷新 |
| 大量对象 | Memory | 减少 Allocation |
| SDK 初始化 | Startup | 延迟初始化 |
二十三、实际开发中的性能判断方式
我一般不会看到:
dart
耗时操作
就马上上 Isolate。
而是先分析 6 个维度:
dart
Flutter Performance
│
├── CPU
│ ├ JSON
│ ├ Sort
│ ├ Loop
│ ├ Encrypt
│ └ Algorithm
│
├── IO
│ ├ HTTP
│ ├ File
│ ├ Database
│ └ Socket
│
├── UI
│ ├ Build
│ ├ Layout
│ └ Paint
│
├── Memory
│ ├ Allocation
│ ├ Image
│ ├ Cache
│ └ GC
│
├── Frequency
│ ├ 一次
│ ├ 每秒10次
│ └ 每秒100次
│
└── Algorithm
├ O(1)
├ O(n)
├ O(n log n)
└ O(n²)
特别需要注意:
👉🏻 性能问题很多时候不是某一行代码特别慢。
而是:
dart
一个 2ms 的方法
×
每秒执行 100 次
最终变成性能问题。
二十四、交易所 Flutter APP 的典型性能链路
如果是交易所 APP,我认为最需要注意的是这一条链路:
dart
WebSocket
↓
JSON Decode
↓
Model.fromJson
↓
List 查找
↓
List 更新
↓
排序
↓
状态通知
↓
Widget Rebuild
↓
Kline / OrderBook Paint
这里面每一步单独拿出来:
dart
可能都不慢
但如果:
dart
每秒执行几十次
全部串起来以后:
👉🏻 就可能成为明显的性能瓶颈。
所以我的优化思路一般是:
dart
降低频率
+
降低数据量
+
降低算法复杂度
+
减少对象创建
+
减少 Widget Rebuild
+
CPU 重任务放 Isolate
而不是简单地:
dart
看到卡顿
↓
加 Isolate
二十五、总结
Flutter 性能优化其实可以归结成一个非常简单的问题:
👉🏻 Main Isolate 到底在忙什么?
如果它只是:
text
等待网络
通常不会造成严重 UI 卡顿。
但如果它一直在:
text
解析 JSON
排序
遍历
加密
计算指标
处理图片
创建对象
刷新 Widget
那就很容易出现:
dart
Jank
所以我们可以记住几个核心原则:
👉🏻 IO 操作优先使用 async / await
👉🏻 CPU 密集型任务考虑 Isolate
👉🏻 高频任务优先考虑 Throttle / Batch
👉🏻 大数据优先优化算法复杂度
👉🏻 实时数据优先做增量更新
👉🏻 UI 状态尽量局部刷新
👉🏻 减少临时对象,降低 GC 压力
👉🏻 不要为了"异步"而滥用 Isolate
真正的 Flutter 性能优化,不是:
哪里卡,就把哪里丢到线程里。
而是:
先找到 Main Isolate 为什么忙,再决定是降低频率、优化算法、减少刷新,还是把计算迁移到 Isolate。