Flutter中的Completer

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

   Completer是Dart/Flutter中用于手动控制Future完成时机的类。它允许将一个异步操作的结果"承诺"(Future)与完成该承诺的控制权分离开来。

  • Future:一个将在未来某个时间点返回结果或错误的承诺

  • Completer:控制Future何时完成的"控制器"

  • Future vs Completer

    • Future是"被承诺者"(被动等待结果)

    • Completer是"承诺者"(主动决定何时完成)

二、基本结构

import 'dart:async';

void main() async {
  // 1. 创建Completer
  Completer<String> completer = Completer<String>();
  
  // 2. 获取对应的Future
  Future<String> future = completer.future;
  
  // 3. 监听Future的结果
  future.then((value) {
    print('Future完成,结果: $value');
  }).catchError((error) {
    print('Future出错: $error');
  });
  
  // 4. 模拟异步操作后完成Completer
  Future.delayed(Duration(seconds: 2), () {
    // 完成Future并传递结果
    completer.complete('操作成功!');
    
    // 或者如果出错:
    // completer.completeError('操作失败');
  });
}

三、Completer主要方法

1. complete(value) - 成功完成Future

Completer<int> completer = Completer<int>();
completer.complete(42);  // Future将返回42

2. completeError(error, [stackTrace]) - 以错误完成Future

Completer<String> completer = Completer<String>();
completer.completeError(Exception('操作失败'));

3. future - 获取对应的Future对象

Future<String> myFuture = completer.future;

4. isCompleted - 检查是否已完成

if (!completer.isCompleted) {
  completer.complete('现在完成');
}

四、实际应用

1:将回调函数转换为Future(最常用)

import 'dart:async';

// 传统回调函数
void fetchDataWithCallback(Function(String) callback) {
  // 模拟网络请求
  Future.delayed(Duration(seconds: 1), () {
    callback('数据加载完成');
  });
}

// 使用Completer转换为Future
Future<String> fetchDataAsFuture() {
  Completer<String> completer = Completer<String>();
  
  fetchDataWithCallback((result) {
    if (result.contains('完成')) {
      completer.complete(result);
    } else {
      completer.completeError(Exception('数据加载失败'));
    }
  });
  
  return completer.future;
}

// 使用方式
void useFuture() async {
  try {
    String result = await fetchDataAsFuture();
    print('结果: $result');
  } catch (e) {
    print('错误: $e');
  }
}

2:手动控制多个异步操作的完成

Future<List<String>> fetchMultipleResources() {
  Completer<List<String>> completer = Completer<List<String>>();
  List<String> results = [];
  int completedCount = 0;
  const totalTasks = 3;
  
  // 模拟多个异步任务
  for (int i = 0; i < totalTasks; i++) {
    Future.delayed(Duration(seconds: i + 1), () async {
      // 模拟获取数据
      String data = await fetchItem(i);
      results.add(data);
      completedCount++;
      
      // 所有任务完成后完成Completer
      if (completedCount == totalTasks) {
        completer.complete(results);
      }
    });
  }
  
  return completer.future;
}

Future<String> fetchItem(int index) async {
  await Future.delayed(Duration(milliseconds: 500));
  return '项目 $index 数据';
}

3:超时控制

Future<String> fetchWithTimeout(Duration timeout) {
  Completer<String> completer = Completer<String>();
  
  // 开始实际的数据获取
  startFetching().then((value) {
    if (!completer.isCompleted) {
      completer.complete(value);
    }
  }).catchError((error) {
    if (!completer.isCompleted) {
      completer.completeError(error);
    }
  });
  
  // 设置超时
  Future.delayed(timeout, () {
    if (!completer.isCompleted) {
      completer.completeError(
        TimeoutException('操作超时', timeout)
      );
    }
  });
  
  return completer.future;
}

4:状态管理

class AuthenticationService {
  Completer<void> _loginCompleter;
  
  Future<void> login(String username, String password) {
    _loginCompleter = Completer<void>();
    
    // 模拟登录请求
    _performLogin(username, password);
    
    return _loginCompleter.future;
  }
  
  void _performLogin(String username, String password) {
    // 模拟网络请求
    Future.delayed(Duration(seconds: 2), () {
      if (username == 'admin' && password == '123456') {
        _loginCompleter?.complete();
      } else {
        _loginCompleter?.completeError(Exception('登录失败'));
      }
      _loginCompleter = null;
    });
  }
  
  void cancelLogin() {
    if (_loginCompleter != null && !_loginCompleter.isCompleted) {
      _loginCompleter.completeError(CancelledException('用户取消'));
      _loginCompleter = null;
    }
  }
}

五、Completer的替代方案

1. 使用StreamController

// 当需要多个值时,使用StreamController更合适
StreamController<String> controller = StreamController<String>();
Stream<String> stream = controller.stream;

controller.add('值1');
controller.add('值2');
controller.close();

2. 直接返回Future

// 如果可以,尽量使用async/await直接创建Future
Future<String> simpleFuture() async {
  await Future.delayed(Duration(seconds: 1));
  return '完成';
}

### 如何在 Flutter 中使用 Future 进行异步操作 #### 使用 `Future` 执行简单的异步任务 在 Dart 和 Flutter 中,`Future` 表示一个可能在未来某个时间点完成的操作。可以用来获取单一的结果或错误。 ```dart import 'dart:async'; void fetchData() async { try { var result = await performNetworkRequest(); print('Data fetched successfully: $result'); } catch (e) { print('Failed to fetch data: $e'); } } Future<String> performNetworkRequest() { return Future.delayed(Duration(seconds: 2), () => "Sample Data"); } ``` 这段代码展示了如何定义并调用一个返回 `Future` 的函数,在其中模拟了一个网络请求的过程[^3]。 #### 处理多个依赖的异步任务 如果存在多个相互依赖的任务,则可以通过链式调用 `.then()` 或者更推荐的方式——利用 `async/await` 来简化逻辑: ```dart void processMultipleTasks() async { final firstResult = await taskOne(); final secondResult = await taskTwo(firstResult); print('Both tasks completed with results: $firstResult and $secondResult'); } Future<int> taskOne() => Future.value(10); Future<String> taskTwo(int input) => Future.value('$input processed'); ``` 这里展示的是两个连续执行的任务,第二个任务取决于第一个任务的成功完成。 #### 并发运行独立的异步任务 对于不互相依赖的任务,可以并发地启动它们,并等待全部完成后继续下一步: ```dart void runIndependentTasksConcurrently() async { List<Future> futures = [ independentTaskA(), independentTaskB() ]; // Wait for all Futures to complete. List results = await Future.wait(futures); print(results); // prints the list of results from both functions } Future<String> independentTaskA() => Future.delayed(Duration(seconds: 1), () => "Task A"); Future<String> independentTaskB() => Future.delayed(Duration(seconds: 2), () => "Task B"); ``` 此例子说明了怎样同时发起几个不会影响彼此进度的任务,并收集其结果[^4]。 #### 错误处理机制 为了确保应用程序能够优雅地应对可能出现的问题,应该总是包含适当的异常捕获措施: ```dart void handleErrorsInFutures() async { try { String response = await potentiallyFailingOperation(); print(response); } on TimeoutException catch (_) { print("The operation timed out."); } catch (error) { print("An unexpected error occurred: ${error.toString()}"); } } Future<String> potentiallyFailingOperation() { throw Exception('Something went wrong!'); } ``` 上述片段显示了不同类型的异常捕捉方法以及如何针对特定情况作出反应。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值