Flutter任务取消管理插件cancellation_token的使用

发布于 1周前 作者 gougou168 来自 Flutter

Flutter任务取消管理插件cancellation_token的使用

Dart Cancellation Token

Dart Cancellation Token 是一个用于轻松实现异步任务取消的工具包。它可以帮助开发者在Flutter应用中取消Futures并清理资源(例如关闭HttpClient),当Widget被销毁时,或者复用单个CancellationToken来取消多个任务。

功能特性

  • 取消Futures和清理资源:当Flutter中的Widget被销毁时,可以取消所有使用该Token的任务。
  • 复用CancellationToken:可以通过调用.cancel()方法一次性取消多个任务。
  • 取消Isolates:通过cancellableCompute取消Isolate。
  • 创建自定义可取消对象:使用Cancellable mixin创建自己的可取消逻辑。

Cancellation Tokens 类型

CancellationToken

标准的CancellationToken用于手动取消任务。调用.cancel()后,所有使用此令牌的任务都会被取消,默认情况下会抛出CancelledException异常,也可以传递自定义异常。

TimeoutCancellationToken

用于在特定时间后取消任务。默认情况下,超时时会抛出TimeoutException异常,可通过timeoutException参数设置自定义异常。使用lazyStart参数控制计时器是否立即开始。

MergedCancellationToken

合并多个CancellationToken。创建时可以使用构造函数或现有Token上的.merge()方法。注意,合并后的取消异常不一定来自最先取消的那个Token。

使用示例

以下是一个完整的Flutter Demo应用程序,演示了如何使用Cancellation Token进行任务管理和取消:

import 'package:cancellation_token/cancellation_token.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Cancellation Token Demo',
      home: DemoPage(),
    );
  }
}

class DemoPage extends StatefulWidget {
  @override
  _DemoPageState createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  final Map<String, String> _taskStatus = {
    'Delayed Future': 'Stopped',
    'Simultaneous A': 'Stopped',
    'Simultaneous B': 'Stopped',
    'Simultaneous C': 'Stopped',
    'Isolate': 'Stopped',
  };
  CancellationToken? _cancellationToken;

  Future<void> _startTasks() async {
    // 取消当前运行的任务并创建新的CancellationToken
    _cancellationToken?.cancel();
    _cancellationToken = CancellationToken();

    // 重置任务状态
    setState(() => _taskStatus.updateAll((key, value) => 'Stopped'));

    try {
      // 启动延迟Future
      setState(() => _taskStatus['Delayed Future'] = 'Running');
      await delayedFuture().asCancellable(_cancellationToken);
      setState(() => _taskStatus['Delayed Future'] = 'Complete');

      // 并行启动多个延迟Future
      setState(() {
        _taskStatus['Simultaneous A'] = 'Running';
        _taskStatus['Simultaneous B'] = 'Running';
        _taskStatus['Simultaneous C'] = 'Running';
      });
      await Future.wait([
        delayedFuture().asCancellable(_cancellationToken).then((_) =>
            setState(() => _taskStatus['Simultaneous A'] = 'Complete')),
        delayedFuture().asCancellable(_cancellationToken).then((_) =>
            setState(() => _taskStatus['Simultaneous B'] = 'Complete')),
        delayedFuture().asCancellable(_cancellationToken).then((_) =>
            setState(() => _taskStatus['Simultaneous C'] = 'Complete')),
      ]);

      // 在隔离区中执行任务
      setState(() => _taskStatus['Isolate'] = 'Running');
      await CancellableIsolate.run(
        () => delayedIsolateFunction(Duration(seconds: 2)),
        _cancellationToken,
      );
      setState(() => _taskStatus['Isolate'] = 'Complete');
    } on CancelledException {
      // 忽略取消异常
    } catch (e) {
      // 处理其他异常
    }
  }

  @override
  void dispose() {
    _cancellationToken?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Cancellation Token Demo')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ..._taskStatus.entries.map((entry) => ListTile(
              title: Text('${entry.key} status'),
              subtitle: Text(entry.value),
            )),
            SizedBox(height: 16.0),
            ElevatedButton(
              onPressed: _startTasks,
              child: Text('Run Tasks'),
            ),
            ElevatedButton(
              onPressed: () => _cancellationToken?.cancel(),
              child: Text('Cancel Running Tasks'),
            ),
          ],
        ),
      ),
    );
  }
}

/// 模拟延迟操作
Future<void> delayedFuture() async {
  await Future.delayed(Duration(seconds: Random().nextInt(5) + 1));
}

/// 模拟隔离区任务
void delayedIsolateFunction(Duration delay) {
  print('Isolate started - Waiting ${delay.inSeconds} seconds');
  sleep(delay);
  print('Isolate finished');
}

这个例子展示了如何使用cancellation_token库来管理Flutter应用中的异步任务,并提供了取消这些任务的能力。你可以根据需要调整和扩展代码以适应具体的应用场景。


更多关于Flutter任务取消管理插件cancellation_token的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter任务取消管理插件cancellation_token的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用cancellation_token插件进行任务取消管理的示例代码。这个插件允许你在执行长时间运行的任务时,能够优雅地取消这些任务。

首先,确保你已经在pubspec.yaml文件中添加了cancellation_token依赖:

dependencies:
  flutter:
    sdk: flutter
  cancellation_token: ^x.y.z  # 请替换为最新版本号

然后,运行flutter pub get来安装依赖。

接下来,我们来看一个完整的示例,展示如何使用cancellation_token来管理任务的取消。

示例代码

import 'package:flutter/material.dart';
import 'package:cancellation_token/cancellation_token.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Cancellation Token Example'),
        ),
        body: Center(
          child: CancellationTokenExample(),
        ),
      ),
    );
  }
}

class CancellationTokenExample extends StatefulWidget {
  @override
  _CancellationTokenExampleState createState() => _CancellationTokenExampleState();
}

class _CancellationTokenExampleState extends State<CancellationTokenExample> {
  CancellationTokenSource? _cancellationTokenSource;

  void _startLongRunningTask() {
    // 创建一个新的CancellationTokenSource
    _cancellationTokenSource = CancellationTokenSource();
    final CancellationToken token = _cancellationTokenSource!.token;

    // 模拟一个长时间运行的任务
    Future.delayed(Duration(seconds: 10), () {
      if (!token.isCancellationRequested) {
        // 如果任务没有被取消,则更新UI
        setState(() {
          // 例如,显示任务完成的信息
        });
      }
    });

    // 在另一个线程中定期检查取消请求
    _checkCancellation(token);
  }

  void _checkCancellation(CancellationToken token) async {
    while (true) {
      await Future.delayed(Duration(milliseconds: 100)); // 每100毫秒检查一次
      if (token.isCancellationRequested) {
        print('Task was cancelled.');
        // 可以在这里执行清理操作
        break;
      }
    }
  }

  void _cancelTask() {
    _cancellationTokenSource?.requestCancellation();
    _cancellationTokenSource = null; // 重置源,以便可以开始新任务
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: _startLongRunningTask,
          child: Text('Start Long Running Task'),
        ),
        SizedBox(height: 20),
        ElevatedButton(
          onPressed: _cancelTask,
          child: Text('Cancel Task'),
        ),
      ],
    );
  }
}

解释

  1. 依赖添加:在pubspec.yaml中添加cancellation_token依赖。
  2. 创建CancellationTokenSource:在_startLongRunningTask方法中,创建一个新的CancellationTokenSource实例,并获取其token
  3. 模拟长时间任务:使用Future.delayed模拟一个长时间运行的任务。在这个例子中,任务将在10秒后完成,但如果在任务完成前请求取消,它将不会更新UI。
  4. 定期检查取消请求:在_checkCancellation方法中,使用一个无限循环每100毫秒检查一次是否请求了取消。如果请求了取消,则打印一条消息并退出循环。
  5. 请求取消:在_cancelTask方法中,调用_cancellationTokenSource?.requestCancellation()来请求取消任务,并将_cancellationTokenSource重置为null,以便可以开始新任务。

这个示例展示了如何使用cancellation_token插件来管理Flutter中的任务取消。你可以根据实际需求对代码进行修改和扩展。

回到顶部