flutter-concurrency
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFlutter Concurrency and Data Management
Flutter 并发与数据管理
Goal
目标
Implements advanced Flutter data handling, including background JSON serialization using Isolates, asynchronous state management, and platform-aware concurrency to ensure jank-free 60fps+ UI rendering. Assumes a standard Flutter environment (Dart 2.19+) with access to , , and standard state management paradigms.
dart:convertdart:isolate实现高级Flutter数据处理能力,包括使用Isolate进行后台JSON序列化、异步状态管理,以及适配平台的并发机制,确保无卡顿的60fps+ UI渲染。本文假设你使用标准Flutter环境(Dart 2.19及以上版本),可使用、以及标准状态管理范式。
dart:convertdart:isolateDecision Logic
决策逻辑
Use the following decision tree to determine the correct serialization and concurrency approach before writing code:
- Serialization Strategy:
- Condition: Is the JSON model simple, flat, and rarely changed?
- Action: Use Manual Serialization ().
dart:convert
- Action: Use Manual Serialization (
- Condition: Is the JSON model complex, nested, or part of a large-scale application?
- Action: Use Code Generation (and
json_serializable).build_runner
- Action: Use Code Generation (
- Condition: Is the JSON model simple, flat, and rarely changed?
- Concurrency Strategy:
- Condition: Is the data payload small and parsing takes < 16ms?
- Action: Run on the Main UI Isolate using standard /
async.await
- Action: Run on the Main UI Isolate using standard
- Condition: Is the data payload large (e.g., > 1MB JSON) or computationally expensive?
- Action: Offload to a Background Isolate using .
Isolate.run()
- Action: Offload to a Background Isolate using
- Condition: Does the background task require continuous, two-way communication over time?
- Action: Implement a Long-lived Isolate using and
ReceivePort.SendPort
- Action: Implement a Long-lived Isolate using
- Condition: Is the target platform Web?
- Action: Use as a fallback, as standard
compute()threading is not supported on Flutter Web.dart:isolate
- Action: Use
- Condition: Is the data payload small and parsing takes < 16ms?
编写代码前,可参考以下决策树选择合适的序列化与并发方案:
- 序列化策略:
- 条件: JSON模型是否简单扁平化、且很少变更?
- 操作: 使用手动序列化()。
dart:convert
- 操作: 使用手动序列化(
- 条件: JSON模型是否复杂、嵌套层级多,或是属于大型应用的一部分?
- 操作: 使用代码生成(和
json_serializable)。build_runner
- 操作: 使用代码生成(
- 条件: JSON模型是否简单扁平化、且很少变更?
- 并发策略:
- 条件: 数据载荷是否很小,解析耗时小于16ms?
- 操作: 使用标准/
async在主UI Isolate中运行。await
- 操作: 使用标准
- 条件: 数据载荷较大(比如大于1MB的JSON)或计算开销高?
- 操作: 使用将任务转移到后台Isolate执行。
Isolate.run()
- 操作: 使用
- 条件: 后台任务是否需要持续的双向通信?
- 操作: 使用和
ReceivePort实现长生命周期Isolate。SendPort
- 操作: 使用
- 条件: 目标平台是否为Web?
- 操作: 使用作为兜底方案,因为Flutter Web不支持标准
compute()线程能力。dart:isolate
- 操作: 使用
- 条件: 数据载荷是否很小,解析耗时小于16ms?
Instructions
使用说明
1. Determine Environment and Payload Context
1. 确定环境与载荷上下文
STOP AND ASK THE USER:
- "Are you targeting Flutter Web, Mobile, or Desktop?"
- "What is the expected size and complexity of the JSON payload?"
- "Do you prefer manual JSON serialization or code generation ()?"
json_serializable
先询问用户以下信息:
- "你的目标平台是Flutter Web、移动端还是桌面端?"
- "JSON载荷的预期大小和复杂度是怎样的?"
- "你倾向于使用手动JSON序列化还是代码生成()?"
json_serializable
2. Implement JSON Serialization Models
2. 实现JSON序列化模型
Based on the user's preference, implement the data models.
Option A: Manual Serialization
dart
import 'dart:convert';
class User {
final String name;
final String email;
User(this.name, this.email);
User.fromJson(Map<String, dynamic> json)
: name = json['name'] as String,
email = json['email'] as String;
Map<String, dynamic> toJson() => {'name': name, 'email': email};
}Option B: Code Generation ()
Ensure is in , and / are in .
json_serializablejson_annotationdependenciesbuild_runnerjson_serializabledev_dependenciesdart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
(explicitToJson: true)
class User {
final String name;
(name: 'email_address', defaultValue: 'unknown@example.com')
final String email;
User(this.name, this.email);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}Validate-and-Fix: Instruct the user to run to generate the file.
dart run build_runner build --delete-conflicting-outputs*.g.dart根据用户的选择实现数据模型。
选项A:手动序列化
dart
import 'dart:convert';
class User {
final String name;
final String email;
User(this.name, this.email);
User.fromJson(Map<String, dynamic> json)
: name = json['name'] as String,
email = json['email'] as String;
Map<String, dynamic> toJson() => {'name': name, 'email': email};
}选项B:代码生成()
确保在中,/在中。
json_serializablejson_annotationdependenciesbuild_runnerjson_serializabledev_dependenciesdart
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
(explicitToJson: true)
class User {
final String name;
(name: 'email_address', defaultValue: 'unknown@example.com')
final String email;
User(this.name, this.email);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}验证与修复: 指导用户执行生成文件。
dart run build_runner build --delete-conflicting-outputs*.g.dart3. Implement Background Parsing (Isolates)
3. 实现后台解析(Isolate)
To prevent UI jank, offload heavy JSON parsing to a background isolate.
Option A: Short-lived Isolate (Dart 2.19+)
Use for one-off heavy computations.
Isolate.run()dart
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/services.dart';
Future<List<User>> fetchAndParseUsers() async {
// 1. Load data on the main isolate
final String jsonString = await rootBundle.loadString('assets/large_users.json');
// 2. Spawn an isolate, pass the computation, and await the result
final List<User> users = await Isolate.run<List<User>>(() {
// This runs on the background isolate
final List<dynamic> decoded = jsonDecode(jsonString) as List<dynamic>;
return decoded.cast<Map<String, dynamic>>().map(User.fromJson).toList();
});
return users;
}Option B: Long-lived Isolate (Continuous Data Stream)
Use and for continuous communication.
ReceivePortSendPortdart
import 'dart:isolate';
Future<void> setupLongLivedIsolate() async {
final ReceivePort mainReceivePort = ReceivePort();
await Isolate.spawn(_backgroundWorker, mainReceivePort.sendPort);
final SendPort backgroundSendPort = await mainReceivePort.first as SendPort;
// Send data to the background isolate
final ReceivePort responsePort = ReceivePort();
backgroundSendPort.send(['https://api.example.com/data', responsePort.sendPort]);
final result = await responsePort.first;
print('Received from background: $result');
}
static void _backgroundWorker(SendPort mainSendPort) async {
final ReceivePort workerReceivePort = ReceivePort();
mainSendPort.send(workerReceivePort.sendPort);
await for (final message in workerReceivePort) {
final String url = message[0] as String;
final SendPort replyPort = message[1] as SendPort;
// Perform heavy work here
final parsedData = await _heavyNetworkAndParse(url);
replyPort.send(parsedData);
}
}为避免UI卡顿,将重度JSON解析转移到后台Isolate执行。
选项A:短生命周期Isolate(Dart 2.19及以上)
使用执行一次性的重度计算任务。
Isolate.run()dart
import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/services.dart';
Future<List<User>> fetchAndParseUsers() async {
// 1. 在主Isolate加载数据
final String jsonString = await rootBundle.loadString('assets/large_users.json');
// 2. 生成Isolate,传入计算逻辑并等待结果
final List<User> users = await Isolate.run<List<User>>(() {
// 以下代码在后台Isolate运行
final List<dynamic> decoded = jsonDecode(jsonString) as List<dynamic>;
return decoded.cast<Map<String, dynamic>>().map(User.fromJson).toList();
});
return users;
}选项B:长生命周期Isolate(持续数据流场景)
使用和实现持续通信。
ReceivePortSendPortdart
import 'dart:isolate';
Future<void> setupLongLivedIsolate() async {
final ReceivePort mainReceivePort = ReceivePort();
await Isolate.spawn(_backgroundWorker, mainReceivePort.sendPort);
final SendPort backgroundSendPort = await mainReceivePort.first as SendPort;
// 向后台Isolate发送数据
final ReceivePort responsePort = ReceivePort();
backgroundSendPort.send(['https://api.example.com/data', responsePort.sendPort]);
final result = await responsePort.first;
print('从后台接收到数据: $result');
}
static void _backgroundWorker(SendPort mainSendPort) async {
final ReceivePort workerReceivePort = ReceivePort();
mainSendPort.send(workerReceivePort.sendPort);
await for (final message in workerReceivePort) {
final String url = message[0] as String;
final SendPort replyPort = message[1] as SendPort;
// 在此执行重度任务
final parsedData = await _heavyNetworkAndParse(url);
replyPort.send(parsedData);
}
}4. Integrate with UI State Management
4. 与UI状态管理集成
Bind the asynchronous isolate computation to the UI using to ensure the main thread remains responsive.
FutureBuilderdart
import 'package:flutter/material.dart';
class UserListScreen extends StatefulWidget {
const UserListScreen({super.key});
State<UserListScreen> createState() => _UserListScreenState();
}
class _UserListScreenState extends State<UserListScreen> {
late Future<List<User>> _usersFuture;
void initState() {
super.initState();
_usersFuture = fetchAndParseUsers(); // Calls the Isolate.run method
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Users')),
body: FutureBuilder<List<User>>(
future: _usersFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('No users found.'));
}
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
);
},
),
);
}
}使用将异步Isolate计算结果绑定到UI,确保主线程保持响应。
FutureBuilderdart
import 'package:flutter/material.dart';
class UserListScreen extends StatefulWidget {
const UserListScreen({super.key});
State<UserListScreen> createState() => _UserListScreenState();
}
class _UserListScreenState extends State<UserListScreen> {
late Future<List<User>> _usersFuture;
void initState() {
super.initState();
_usersFuture = fetchAndParseUsers(); // 调用Isolate.run方法
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('用户列表')),
body: FutureBuilder<List<User>>(
future: _usersFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('错误: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('未找到用户数据。'));
}
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
);
},
),
);
}
}Constraints
约束条件
- No UI in Isolates: Never attempt to access ,
dart:ui, or manipulate Flutter Widgets inside a spawned isolate. Isolates do not share memory with the main thread.rootBundle - Web Platform Limitations: is not supported on Flutter Web. If targeting Web, you MUST use the
dart:isolatefunction fromcompute()instead ofpackage:flutter/foundation.dart, asIsolate.run()safely falls back to the main thread on web platforms.compute() - Immutable Messages: When passing data between isolates via , prefer passing immutable objects (like Strings or unmodifiable byte data) to avoid deep-copy performance overhead.
SendPort - State Immutability: Always treat properties as immutable. Use
WidgetandStatefulWidget(or a state management package) to trigger rebuilds when asynchronous data resolves.setState - Reflection: Do not use for JSON serialization. Flutter disables runtime reflection to enable aggressive tree-shaking and AOT compilation. Always use manual parsing or code generation.
dart:mirrors
- Isolate中不能操作UI: 绝对不要在生成的Isolate中访问、
dart:ui或者操作Flutter Widget,Isolate和主线程不共享内存。rootBundle - Web平台限制: Flutter Web不支持,如果目标平台是Web,必须使用
dart:isolate中的package:flutter/foundation.dart函数替代compute(),Isolate.run()会在Web平台安全地回退到主线程执行。compute() - 不可变消息: 通过在Isolate之间传递数据时,优先传递不可变对象(比如字符串或者不可修改的字节数据),避免深拷贝带来的性能开销。
SendPort - 状态不可变性: 始终将属性视为不可变,异步数据返回后,使用
Widget和StatefulWidget(或者状态管理包)触发UI重绘。setState - *反射: 不要使用做JSON序列化,Flutter禁用了运行时反射以支持高效的树抖动和AOT编译,始终使用手动解析或者代码生成方案。
dart:mirrors