【Flutter】Flutter 中有哪些耗时操作?从 UI 卡顿到 Isolate 性能优化

【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。


相关推荐
政企项目老覃2 小时前
金融转账“幽灵失败“排查实录:从本地消息表到 Seata TCC 的选型与权衡
数据库·程序人生·性能优化·数据分析·系统架构
sakiko_2 小时前
Flutter:Dart学习笔记1:基础UI组件等
flutter
爱喝水的鱼丶3 小时前
SAP-ABAP:MM 模块供应商主数据开发:字段扩展、分级管控与同步接口开发
开发语言·性能优化·接口·sap·abap·增强·经验交流
贾伟康3 小时前
【HarmonyOS 7新能力|050】Core File Kit mmap工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·文件系统·mmap
9765033353 小时前
iOS 上架 4.3a 被拒【uniapp专讲】
flutter·ios·objective-c·uniapp·swift
贾伟康3 小时前
【HarmonyOS 7新能力|045】LazyLayoutAlgorithm工程封装:把接入逻辑放进可维护的分层结构
性能优化·harmonyos·arkts·arkui·懒加载
打工仔折腾 AI3 小时前
数据库上 K8s 之后谁来管?拆解金仓 KES-Operator 的声明式运维方案
人工智能·后端·python·性能优化·ai agent 实战
hanchenxing4 小时前
正则表达式回溯陷阱:用最小示例避开灾难性回溯正则表达式
性能优化·回溯陷阱
HwJack2016 小时前
【HarmonyOS开发小实践】ArkUI 动画系统属性动画、显式动画与路径动画
ui·性能优化·harmonyos