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

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

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

简介

cancellation_token_hoc081098 是一个受 C# 中的 CancellationToken 启发的 Dart 实用程序包,旨在简化异步任务的取消和资源清理。

主要功能

  • 复用:可以复用单个 CancellationToken 来取消多个任务。
  • 取消 Futures 和 Streams:提供 token.guardFuture(block)token.guardStream(stream) 方法来取消 Future 和 Stream,并清理资源。
  • 与 rxdart 集成:支持通过 useCancellationToken 与 rxdart/rxdart_ext 集成。
  • 简单、轻量、高效且易于使用

使用步骤

1. 添加依赖

pubspec.yaml 文件中添加以下依赖:

dependencies:
  cancellation_token_hoc081098: <latest_version>

2. 导入包

在 Dart 文件中导入该包:

import 'package:cancellation_token_hoc081098/cancellation_token_hoc081098.dart';

示例代码

1. 使用 guardFuture

void main() async {
  // 创建 CancellationToken
  final token = CancellationToken();

  // 模拟一个长时间运行的任务
  Future<void> doWork(int number) async {
    print('doWork($number) started');
    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('doWork($number) finished');
  }

  // 使用 guardFuture 保护 Future
  final future = token.guardFuture(() async {
    for (var i = 0; i < 10; i++) {
      token.guard(); // 如果 token 被取消则抛出异常
      await doWork(i);
      token.guard(); // 如果 token 被取消则抛出异常
    }
    return 42;
  });

  future
      .then((v) => print('Result: $v'))
      .onError<Object>((e, st) => print('Error: $e'));

  // 在 300ms 后取消 token
  await Future<void>.delayed(const Duration(milliseconds: 300));

  // 取消 token
  token.cancel();

  // 等待一段时间以确保 Future 已被取消
  await Future<void>.delayed(const Duration(seconds: 2));

  // 输出示例:
  // doWork(0) started
  // doWork(0) finished
  // doWork(1) started
  // doWork(1) finished
  // doWork(2) started
  // Error: CancellationException
  // doWork(2) finished
}

2. 使用 guardStream

void main() async {
  // 创建 CancellationToken
  final token = CancellationToken();

  // 模拟一个长时间运行的任务
  Future<void> doWork(int number) async {
    print('doWork($number) started');
    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('doWork($number) finished');
  }

  // 使用 guardStream 保护 Stream
  final stream = Rx.fromCallable(() async {
    for (var i = 0; i < 10; i++) {
      token.guard(); // 如果 token 被取消则抛出异常
      await doWork(i);
      token.guard(); // 如果 token 被取消则抛出异常
    }
    return 42;
  }).guardedBy(token);

  stream
      .doOnData((v) => print('Result: $v'))
      .doOnError((e, st) => print('Error: $e'))
      .listen(null);

  // 在 300ms 后取消 token
  await Future<void>.delayed(const Duration(milliseconds: 300));

  // 取消 token
  token.cancel();

  // 等待一段时间以确保 Stream 已被取消
  await Future<void>.delayed(const Duration(seconds: 2));

  // 输出示例:
  // doWork(0) started
  // doWork(0) finished
  // doWork(1) started
  // doWork(1) finished
  // doWork(2) started
  // Error: CancellationException
  // doWork(2) finished
}

3. 使用 useCancellationToken

import 'package:rxdart_ext/rxdart_ext.dart';

void main() async {
  // 模拟一个长时间运行的任务
  Future<void> doWork(int number) async {
    print('doWork($number) started');
    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('doWork($number) finished');
  }

  // 使用 useCancellationToken
  final Single<int> single = useCancellationToken((cancelToken) async {
    for (var i = 0; i < 10; i++) {
      cancelToken.guard(); // 如果 token 被取消则抛出异常
      await doWork(i);
      cancelToken.guard(); // 如果 token 被取消则抛出异常
    }
    return 42;
  });

  final subscription = single
      .doOnData((v) => print('Result: $v'))
      .doOnError((e, st) => print('Error: $e'))
      .listen(null);

  // 在 300ms 后取消订阅
  await Future<void>.delayed(const Duration(milliseconds: 300));

  // 取消订阅
  await subscription.cancel();

  // 等待一段时间以确保流已被取消
  await Future<void>.delayed(const Duration(seconds: 2));

  // 输出示例:
  // doWork(0) started
  // doWork(0) finished
  // doWork(1) started
  // doWork(1) finished
  // doWork(2) started
  // doWork(2) finished
}

完整示例 Demo

以下是完整的示例代码,展示了如何使用 cancellation_token_hoc081098 包的不同功能:

import 'package:cancellation_token_hoc081098/cancellation_token_hoc081098.dart';
import 'package:rxdart_ext/rxdart_ext.dart';

final separator = '-' * 30;

void onError(Object error, StackTrace stackTrace) =>
    print('[onError] error: $error, stackTrace: $stackTrace');

void main() async {
  print('${separator}guardFutureExample$separator');
  await guardFutureExample();

  print('${separator}guardStreamExample$separator');
  await guardStreamExample();

  print('${separator}reuseTokenExample$separator');
  await reuseTokenExample();

  print('${separator}useCancellationToken$separator');
  await useCancellationTokenExample();

  await delay(2000);
  print('${separator}done$separator');
}

Future<void> guardStreamExample() async {
  final token = CancellationToken();

  // 可以使用 stream.guardedBy(token) 替代 token.guardStream(stream)
  final stream = token.guardStream(Rx.fromCallable(() async {
    print('start...');

    token.guard();
    await delay(100);
    token.guard();

    print('Step 1');

    token.guard();
    await delay(100);
    token.guard();

    print('Step 2');

    token.guard();
    await delay(100);
    token.guard();

    print('done...');
    return 42;
  }));

  stream.listen(print, onError: onError);

  await delay(120);
  token.cancel();
  await delay(800);
  print('exit...');
}

Future<void> guardFutureExample() async {
  final token = CancellationToken();

  final future = token.guardFuture((token) async {
    print('start...');

    token.guard();
    await delay(100);
    token.guard();

    print('Step 1');

    token.guard();
    await delay(100);
    token.guard();

    print('Step 2');

    token.guard();
    await delay(100);
    token.guard();

    print('done...');
    return 42;
  });

  future.then(print, onError: onError).ignore();

  await delay(120);
  token.cancel();
  await delay(800);
  print('exit...');
}

Future<void> reuseTokenExample() async {
  final token = CancellationToken();

  final future1 = token.guardFuture((token) async {
    for (var i = 0; i < 10; i++) {
      token.guard();

      print('future1: start $i');
      await delay(100);
      print('future1: end $i');

      token.guard();
    }
  });

  final future2 = token.guardFuture((token) async {
    for (var i = 0; i < 10; i++) {
      token.guard();

      print('future2: start $i');
      await delay(100);
      print('future2: end $i');

      token.guard();
    }
  });

  Future.wait([future1, future2])
      .then((result) => print('result: $result'), onError: onError)
      .ignore();

  await delay(250);
  token.cancel();
  await delay(800);
  print('exit...');
}

Future<void> useCancellationTokenExample() async {
  final single = useCancellationToken((token) async {
    print('start...');

    token.guard();
    await delay(100);
    token.guard();

    print('Step 1');

    token.guard();
    await delay(100);
    token.guard();

    print('Step 2');

    token.guard();
    await delay(100);
    token.guard();

    print('done...');
    return 42;
  });

  final subscription = single.listen(print, onError: onError);

  await delay(120);
  await subscription.cancel();
  await delay(800);
  print('exit...');
}

Future<void> delay(int milliseconds) => Future<void>.delayed(Duration(milliseconds: milliseconds));

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

1 回复

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


当然,以下是一个关于如何在Flutter中使用cancellation_token_hoc081098插件进行任务取消管理的代码示例。这个插件允许你在异步任务执行过程中,通过令牌(token)来取消任务。

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

dependencies:
  flutter:
    sdk: flutter
  cancellation_token_hoc081098: ^latest_version  # 请使用最新版本号

然后运行flutter pub get来获取依赖。

接下来是一个完整的代码示例,展示如何使用这个插件来取消一个异步任务:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final CancellationTokenSource _cancellationTokenSource = CancellationTokenSource();
  bool _isRunning = false;
  String _result = '';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Cancellation Token Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _result,
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _isRunning ? null : _startTask,
              child: Text(_isRunning ? 'Running...' : 'Start Task'),
            ),
            SizedBox(height: 10),
            ElevatedButton(
              onPressed: _isRunning ? _cancelTask : null,
              child: Text(_isRunning ? 'Cancel Task' : ''),
            ),
          ],
        ),
      ),
    );
  }

  void _startTask() {
    setState(() {
      _isRunning = true;
      _result = '';
    });

    _performAsyncTask(_cancellationTokenSource.token).then((result) {
      setState(() {
        _isRunning = false;
        _result = 'Task Result: $result';
      });
    }).catchError((error) {
      if (error is CancellationTokenError) {
        setState(() {
          _isRunning = false;
          _result = 'Task Cancelled';
        });
      } else {
        setState(() {
          _isRunning = false;
          _result = 'Task Error: $error';
        });
      }
    });
  }

  Future<int> _performAsyncTask(CancellationToken token) async {
    for (int i = 0; i <= 10; i++) {
      // Check if the token has been cancelled
      if (token.isCancelled) {
        throw CancellationTokenError();
      }
      
      // Simulate async work with a delay
      await Future.delayed(Duration(seconds: 1));
      print('Task Progress: $i');
    }
    
    return 10;
  }

  void _cancelTask() {
    _cancellationTokenSource.cancel();
  }
}

// Custom error to indicate task cancellation
class CancellationTokenError implements Exception {}

代码解释:

  1. 依赖项:在pubspec.yaml中添加cancellation_token_hoc081098依赖项。
  2. 状态管理:在_MyHomePageState中,我们使用_isRunning来跟踪任务是否正在运行,_result来显示结果。
  3. CancellationTokenSource:创建一个CancellationTokenSource实例,用于生成和管理取消令牌。
  4. 启动任务_startTask方法启动异步任务,并将取消令牌传递给任务函数。
  5. 异步任务_performAsyncTask方法模拟一个异步任务,每秒钟检查一次令牌是否被取消。
  6. 取消任务_cancelTask方法调用_cancellationTokenSource.cancel()来取消任务。
  7. 错误处理:在任务完成时,检查是否有CancellationTokenError来更新UI,显示任务被取消。

这个示例展示了如何使用cancellation_token_hoc081098插件在Flutter中进行任务取消管理。希望这对你有所帮助!

回到顶部