详解Flutter和Dart取消Future的三种方法

使用异步包(推荐)

async包由 Dart 编程语言的作者开发和发布。它提供了dart:async风格的实用程序来增强异步计算。可以帮助我们取消Future的是CancelableOperation类:

1

2

3

4

5

6

7

var myCancelableFuture = CancelableOperation.fromFuture(

  Future inner,

  { FutureOr onCancel()? }

)

// call the cancel() method to cancel the future

myCancelableFuture.cancel();

为了更清楚,请参阅下面的实际示例。

完整示例

应用预览

详解Flutter和Dart取消Future的三种方法_第1张图片

我们要构建的应用程序有一个浮动按钮。按下此按钮时,将开始异步操作(这需要 5 秒才能完成)。按钮的背景从靛蓝变为红色,其标签从“开始”变为“取消”,现在您可以使用它来取消Future。

  • 如果您在Future完成前 5 秒内点击取消按钮,屏幕将显示“Future已被取消”。
  • 如果您什么都不做,则 5 秒后屏幕将显示“Future completed”。

一个演示价值超过一千字:

代码

1.通过执行以下操作安装异步包:

1

flutter pub add async

然后运行:

1

flutter pub get

2.main.dart 中的完整源代码(附解释):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

// main.dart

import 'package:flutter/material.dart';

import 'package:async/async.dart';

void main() {

  runApp(const MyApp());

}

class MyApp extends StatelessWidget {

  const MyApp({Key? key}) : super(key: key);

  @override

  Widget build(BuildContext context) {

    return MaterialApp(

        // Remove the debug banner

        debugShowCheckedModeBanner: false,

        title: '大前端之旅',

        theme: ThemeData(

          primarySwatch: Colors.indigo,

        ),

        home: const HomePage());

  }

}

class HomePage extends StatefulWidget {

  const HomePage({Key? key}) : super(key: key);

  @override

  _HomePageState createState() => _HomePageState();

}

class _HomePageState extends State {

  // this future will return some text once it completes

  Future _myFuture() async {

    await Future.delayed(const Duration(seconds: 5));

    return 'Future completed';

  }

  // keep a reference to CancelableOperation

  CancelableOperation? _myCancelableFuture;

  // This is the result returned by the future

  String? _text;

  // Help you know whether the app is "loading" or not

  bool _isLoading = false;

  // This function is called when the "start" button is pressed

  void _getData() async {

    setState(() {

      _isLoading = true;

    });

    _myCancelableFuture = CancelableOperation.fromFuture(

      _myFuture(),

      onCancel: () => 'Future has been canceld',

    );

    final value = await _myCancelableFuture?.value;

    // update the UI

    setState(() {

      _text = value;

      _isLoading = false;

    });

  }

  // this function is called when the "cancel" button is tapped

  void _cancelFuture() async {

    final result = await _myCancelableFuture?.cancel();

    setState(() {

      _text = result;

      _isLoading = false;

    });

  }

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      appBar: AppBar(title: const Text('大前端之旅')),

      body: Center(

        child: _isLoading

            ? const CircularProgressIndicator()

            : Text(

                _text ?? 'Press Start Button',

                style: const TextStyle(fontSize: 28),

              ),

      ),

      // This button is used to trigger _getDate() and _cancelFuture() functions

      // the function is called depends on the _isLoading variable

      floatingActionButton: ElevatedButton(

        onPressed: () => _isLoading ? _cancelFuture() : _getData(),

        child: Text(_isLoading ? 'Cancel' : 'Start'),

        style: ElevatedButton.styleFrom(

            padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 30),

            primary: _isLoading ? Colors.red : Colors.indigo),

      ),

    );

  }

}

使用 timeout() 方法

这种方法既快速又简单。但是,它不是很灵活。

使用timeout()方法,您可以限制Future的时间(例如 3 秒)。如果 future 及时完成,它的值将被返回。另一方面,如果Future超过限制时间,将执行onTimeout函数:

1

2

3

4

Future timeout(

   Duration timeLimit,

  {FutureOr onTimeout()?}

)

快速示例

创建一个虚拟的Future:

1

2

3

4

Future _myFuture() async {

    await Future.delayed(const Duration(seconds: 10));

    return 'Future completed';

}

设置超时 3 秒:

1

2

3

4

5

_myFuture().timeout(

      const Duration(seconds: 3),

      onTimeout: () =>

          'The process took too much time to finish. Please try again later',

);

将Future转换为流

您可以使用 Future 类的asStream()方法来创建一个包含原始Future结果的流。现在您可以取消对该流的订阅。

快速示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// don't forget to import this

import 'dart:async';

// Create a demo future

Future _loadData() async {

    await Future.delayed(const Duration(seconds: 10));

    return 'Some Data';

}

// a reference to the stream subscription

// so that we can call _sub.cancel() later

StreamSubscription? _sub;

// convert the future to a stream

_sub = _loadData().asStream().listen((data) {

    // do something with "data"

    print(data);

 });

// cancel the stream subscription

_sub.cancel();

请注意,这个快速示例仅简要描述了事物的工作原理。您必须对其进行修改以使其可在现有项目中运行。

结论

你已经学会了不止一种方法来取消 Flutter 中的Future。从其中选择一个以在您的应用程序中实现,以使其在处理异步任务时更加健壮和吸引人。

 

你可能感兴趣的:(flutter)