本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、为什么需要异步?
// 同步操作会阻塞UI
void fetchData() {
final data = http.get('https://api.example.com/data'); // 阻塞3秒
showData(data); // UI在这3秒内完全卡住
}
// 异步操作不阻塞UI
Future<void> fetchData() async {
final response = await http.get('https://api.example.com/data');
showData(response.data); // UI保持流畅
}
Dart 异步三要素
| 概念 | 作用 | 类比 |
|---|---|---|
| Future | 表示一个异步操作的结果 | "承诺" - 未来会有结果 |
| async | 标记函数为异步函数 | "异步环境" |
| await | 等待异步操作完成 | "等待承诺兑现" |
二、Future 使用
// 1. 创建 Future
Future<String> fetchUserName() {
return Future.delayed(
Duration(seconds: 2),
() => 'Flutter Developer',
);
}
// 2. 使用 then() 处理结果
fetchUserName().then((name) {
print('用户名: $name');
}).catchError((error) {
print('获取失败: $error');
}).whenComplete(() {
print('操作完成');
});
// 3. 使用 async/await
Future<void> printUserName() async {
try {
final name = await fetchUserName();
print('用户名: $name');
} catch (error) {
print('获取失败: $error');
} finally {
print('操作完成');
}
}
Future 的状态
class FutureStateTracker<T> {
final Future<T> future;
FutureState state = FutureState.pending;
T? data;
Object? error;
FutureStateTracker(this.future) {
_track();
}
void _track() {
state = FutureState.running;
future.then((value) {
state = FutureState.completed;
data = value;
}).catchError((e) {
state = FutureState.failed;
error = e;
});
}
}
enum FutureState {
pending, // 尚未开始
running, // 执行中
completed, // 完成
failed, // 失败
}
Future 高级操作
// 1. Future.wait - 等待多个 Future 完成
Future<List<String>> fetchMultipleData() async {
final futures = [
fetchUserInfo(),
fetchProductList(),
fetchSettings(),
];
final results = await Future.wait(futures);
return results;
}
// 2. Future.any - 获取第一个完成的 Future
Future<String> getFastestServerResponse() {
final servers = [
_fetchFromServer1(),
_fetchFromServer2(),
_fetchFromServer3(),
];
return Future.any(servers);
}
// 3. Future.doWhile - 循环执行直到条件满足
Future<void> pollUntilReady() {
bool isReady = false;
return Future.doWhile(() async {
await Future.delayed(Duration(seconds: 1));
isReady = await checkStatus();
return !isReady; // 返回 true 继续循环
});
}
// 4. Future.timeout - 设置超时
Future<String> fetchWithTimeout() async {
return await fetchData()
.timeout(Duration(seconds: 5))
.catchError((error) {
if (error is TimeoutException) {
return '超时,使用默认值';
}
throw error;
});
}
// 5. Future.value / Future.error - 创建立即完成的 Future
Future<String> immediateFuture() {
return Future.value('立即完成的值');
}
Future<String> errorFuture() {
return Future.error(Exception('模拟错误'));
}
三、async/await使用
// 错误用法
Future<List<String>> getData() async {
final list1 = await fetchList1(); // 等待3秒
final list2 = await fetchList2(); // 再等待2秒 - 总共5秒
return [...list1, ...list2];
}
// 正确用法 - 并行执行
Future<List<String>> getData() async {
final future1 = fetchList1(); // 立即开始
final future2 = fetchList2(); // 立即开始
final list1 = await future1; // 等待
final list2 = await future2; // 可能已经完成
return [...list1, ...list2]; // 总共约3秒
}
class AsyncBestPractices {
// 不必要的 async
Future<int> unnecessaryAsync(int x, int y) async {
return x + y; // 同步操作不需要 async
}
// 改进
Future<int> betterVersion(int x, int y) {
return Future.value(x + y);
}
// 忘记 await
Future<void> saveData() async {
_database.save(data); // 忘记 await!
print('保存完成'); // 实际上可能还没保存
}
// 改进
Future<void> saveData() async {
await _database.save(data);
print('保存完成');
}
// 异常处理不完整
Future<void> loadData() async {
final data = await fetchData(); // 可能抛出异常
process(data); // 如果上面异常,这里不会执行
}
// 改进
Future<void> loadData() async {
try {
final data = await fetchData();
process(data);
} catch (error) {
print('加载失败: $error');
rethrow; // 或者处理错误
}
}
// await 在循环中顺序执行
Future<void> downloadFiles(List<String> urls) async {
for (final url in urls) {
await downloadFile(url); // 顺序下载,很慢!
}
}
// 改进 - 并行下载
Future<void> downloadFiles(List<String> urls) async {
final futures = urls.map((url) => downloadFile(url));
await Future.wait(futures);
}
}
四、Stream 流式数据
4.1 Stream 使用
// 1. 创建 Stream
Stream<int> countStream(int max) async* {
for (int i = 1; i <= max; i++) {
await Future.delayed(Duration(milliseconds: 100));
yield i; // 产生一个值
}
}
// 2. 监听 Stream
void listenToStream() {
final stream = countStream(5);
final subscription = stream.listen(
(data) => print('收到数据: $data'),
onError: (error) => print('错误: $error'),
onDone: () => print('流结束'),
);
// 可以取消订阅
Future.delayed(Duration(seconds: 1), () {
subscription.cancel();
});
}
// 3. 使用 await for
Future<void> processStream() async {
final stream = countStream(10);
await for (final number in stream) {
print('处理数字: $number');
if (number > 5) break; // 可以提前退出
}
}
4.2 Stream 转换操作
class StreamTransformers {
// 1. map - 转换数据
Stream<String> numberToString(Stream<int> stream) {
return stream.map((number) => '数字: $number');
}
// 2. where - 过滤数据
Stream<int> evenNumbers(Stream<int> stream) {
return stream.where((number) => number % 2 == 0);
}
// 3. take - 取前N个
Stream<int> firstThree(Stream<int> stream) {
return stream.take(3);
}
// 4. skip - 跳过前N个
Stream<int> skipFirstTwo(Stream<int> stream) {
return stream.skip(2);
}
// 5. debounce - 防抖
Stream<T> debounceStream<T>(Stream<T> stream, Duration duration) {
return stream.transform(
StreamTransformer.fromHandlers(
handleData: (data, sink) {
Timer? timer;
timer?.cancel();
timer = Timer(duration, () => sink.add(data));
},
),
);
}
// 6. throttle - 节流
Stream<T> throttleStream<T>(Stream<T> stream, Duration duration) {
return stream.transform(
StreamTransformer.fromHandlers(
handleData: (data, sink) {
final now = DateTime.now();
if (_lastEmitTime == null ||
now.difference(_lastEmitTime!) > duration) {
sink.add(data);
_lastEmitTime = now;
}
},
),
);
}
DateTime? _lastEmitTime;
}
4.3 StreamController 自定义流
class DataStreamManager {
final StreamController<int> _controller = StreamController<int>();
Stream<int> get stream => _controller.stream;
// 添加数据到流
void addData(int data) {
if (!_controller.isClosed) {
_controller.add(data);
}
}
// 添加错误
void addError(Object error) {
if (!_controller.isClosed) {
_controller.addError(error);
}
}
// 关闭流
void close() {
_controller.close();
}
// 广播流(多个监听者)
StreamController<String> _broadcastController =
StreamController<String>.broadcast();
Stream<String> get broadcastStream => _broadcastController.stream;
}
// 使用示例
void manageCustomStream() {
final manager = DataStreamManager();
// 监听流
final subscription = manager.stream.listen(
(data) => print('收到: $data'),
);
// 添加数据
manager.addData(1);
manager.addData(2);
manager.addData(3);
// 清理
subscription.cancel();
manager.close();
}
五、Flutter 中的异步 UI
5.1 FutureBuilder - 异步数据构建 UI
class UserProfile extends StatelessWidget {
Future<User> fetchUser() async {
await Future.delayed(Duration(seconds: 2));
return User(name: '张三', age: 25);
}
@override
Widget build(BuildContext context) {
return FutureBuilder<User>(
future: fetchUser(),
builder: (context, snapshot) {
// 检查连接状态
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
case ConnectionState.done:
if (snapshot.hasError) {
return ErrorWidget(snapshot.error!);
}
if (snapshot.hasData) {
final user = snapshot.data!;
return Column(
children: [
Text('姓名: ${user.name}'),
Text('年龄: ${user.age}'),
],
);
}
return Text('无数据');
}
},
);
}
}
5.2 StreamBuilder - 流式数据构建 UI
class RealTimeCounter extends StatefulWidget {
@override
_RealTimeCounterState createState() => _RealTimeCounterState();
}
class _RealTimeCounterState extends State<RealTimeCounter> {
final StreamController<int> _counterController =
StreamController<int>();
int _counter = 0;
Stream<int> get counterStream async* {
while (true) {
await Future.delayed(Duration(seconds: 1));
yield _counter++;
}
}
@override
void dispose() {
_counterController.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: counterStream,
initialData: 0,
builder: (context, snapshot) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'实时计数器',
style: TextStyle(fontSize: 24),
),
SizedBox(height: 20),
Text(
'${snapshot.data ?? 0}',
style: TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
),
SizedBox(height: 20),
if (snapshot.hasError)
Text('错误: ${snapshot.error}'),
if (snapshot.connectionState == ConnectionState.waiting)
CircularProgressIndicator(),
],
);
},
);
}
}
1949

被折叠的 条评论
为什么被折叠?



