Flutter中 异步的实现方式

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

一、为什么需要异步?

// 同步操作会阻塞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(),
          ],
        );
      },
    );
  }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值