Flutter异步任务管理插件async_phase的使用

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

Flutter异步任务管理插件async_phase的使用

async_phase 是一个用于表示异步操作阶段的包,非常适合在Flutter应用中进行异步任务管理。本文将介绍如何使用 async_phase 包来管理异步任务,并提供完整的示例代码。

关于此包

该包主要用于与 AsyncPhaseNotifier 一起在Flutter应用中使用,但也可以独立用于纯Dart应用。有关 AsyncPhaseNotifier 的详细信息,请参阅其文档

AsyncPhase 类

AsyncPhase 是一个密封类,类似于 package:riverpod 中的 AsyncValue,但它是独立的包,可以避免不必要的依赖,并且没有复杂的行为。

子类(阶段)

AsyncPhase 的四个子类用于表示异步操作的不同阶段:

  • AsyncInitial
  • AsyncWaiting
  • AsyncComplete
  • AsyncError

属性

  • data: 异步操作的结果。
  • error: 发生错误时的错误信息(仅存在于 AsyncError 中)。
  • stackTrace: 错误的堆栈跟踪(仅存在于 AsyncError 中)。

使用方法

以下是如何在不使用 AsyncPhaseNotifier 的情况下使用 async_phase 的示例。

AsyncPhase.from()

使用 AsyncPhase.from() 执行异步函数并将结果转换为 AsyncCompleteAsyncError

示例代码

class WeatherForecast {
  WeatherForecast({required this.onPhaseChanged});

  final void Function(AsyncPhase<Weather>) onPhaseChanged;

  AsyncPhase<Weather> _phase = AsyncInitial(Weather());

  Future<void> fetch() async {
    _phase = _phase.copyAsWaiting();
    onPhaseChanged(_phase);

    _phase = await AsyncPhase.from(
      () => repository.fetchWeather(Cities.tokyo),
      fallbackData: _phase.data,
    );
    onPhaseChanged(_phase);
  }
}

when()

when() 方法用于根据当前阶段返回相应的值或小部件。

final message = phase.when(
  initial: (data) => 'phase: AsyncInitial ($data)', // Optional
  waiting: (data) => 'phase: AsyncWaiting ($data)',
  complete: (data) => 'phase: AsyncComplete ($data)',
  error: (data, error, stackTrace) => 'phase: AsyncError ($error)',
);

模式匹配

作为 when() 的替代方案,可以使用模式匹配处理阶段。

final message = switch (phase) {
  AsyncInitial(:final data) => 'phase: AsyncInitial ($data)',
  AsyncWaiting(:final data) => 'phase: AsyncWaiting ($data)',
  AsyncComplete(:final data) => 'phase: AsyncComplete ($data)',
  AsyncError(:final error) => 'phase: AsyncError ($error)',
};

whenOrNull()

如果只需要某些阶段,可以使用 whenOrNull()

final message = phase.whenOrNull(
  complete: (data) => 'phase: AsyncComplete ($data)',
  error: (data, error, stackTrace) => 'phase: AsyncError ($error)',
);

类型检查

可以使用 isInitial, isWaiting, isComplete, isError 来检查当前阶段。

if (phase is AsyncError<Weather>) {
  print(phase.error);
  return;
}

rethrowError()

AsyncError 提供了 rethrowError() 方法,用于重新抛出错误。

Future<AsyncPhase<Uint8List>> fetchImage({required Uri uri}) async {
  return AsyncPhase.from(() {
    final phase = await downloadFrom(uri: uri);
    if (phase case AsyncError()) {
      phase.rethrowError();
    }
    return resizeImage(phase.data, maxSize: ...);
  });
}

onComplete / onError

onCompleteonError 可以用于在操作成功或失败时执行特定的操作。

final phase = await AsyncPhase.from(
  () => someOperation(),
  onComplete: (data) {
    // Called when the operation completes successfully.
  },
  onError: (data, error, stackTrace) {
    // Called when the operation fails.
  },
);

完整示例

以下是一个完整的示例,展示如何使用 async_phase 进行异步计算。

import 'dart:async';
import 'package:async_phase/async_phase.dart';

Future<void> main() async {
  final calc = Calculation(80.0, onPhaseChanged: _onPhaseChanged);
  await wait();

  for (final divisor in [2, 4, 0]) {
    print('Dividing by $divisor...');
    await wait();

    await calc.divideBy(divisor);
    await wait();
  }
}

void _onPhaseChanged(AsyncPhase<double> phase) {
  final message = phase.when(
    initial: (data) => 'Initial value\n  $data',
    waiting: (data) => '  $data (waiting)',
    complete: (data) => '  $data (complete)',
    error: (data, e, s) => '  $data ($e)',
  );
  print(message);
}

class Calculation {
  Calculation(double initial, {required this.onPhaseChanged}) {
    phase = AsyncInitial(initial);
    onPhaseChanged(phase);
  }

  late AsyncPhase<double> phase;
  late void Function(AsyncPhase<double>) onPhaseChanged;

  Future<void> divideBy(num value) async {
    phase = phase.copyAsWaiting();
    onPhaseChanged(phase);

    phase = await AsyncPhase.from(
      () => phase.data!.divideBy(value),
      fallbackData: -1.0,
    );
    onPhaseChanged(phase);
  }
}

extension on double? {
  double divideBy(num value) {
    if (value == 0) throw ArgumentError('Division by zero');
    return this! / value.toDouble();
  }
}

Future<void> wait([int milliseconds = 500]) => Future.delayed(Duration(milliseconds: milliseconds));

通过上述示例和解释,您应该能够很好地理解并使用 async_phase 包来管理Flutter应用中的异步任务。


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

1 回复

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


在Flutter中,async_phase 是一个用于管理异步任务的插件。它允许你以声明式的方式定义和管理异步任务的各个阶段,使得异步任务的管理更加清晰和高效。以下是一个使用 async_phase 插件的示例代码,展示如何定义和执行异步任务。

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

dependencies:
  flutter:
    sdk: flutter
  async_phase: ^latest_version  # 请替换为最新版本号

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

接下来,是一个完整的 Flutter 应用示例,展示如何使用 async_phase 插件:

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

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

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

class AsyncPhaseDemo extends StatefulWidget {
  @override
  _AsyncPhaseDemoState createState() => _AsyncPhaseDemoState();
}

class _AsyncPhaseDemoState extends State<AsyncPhaseDemo> {
  final AsyncPhaseController _controller = AsyncPhaseController();

  @override
  void initState() {
    super.initState();

    // 定义异步任务
    _controller.definePhase(
      'fetchData',
      () async {
        // 模拟一个网络请求
        await Future.delayed(Duration(seconds: 2));
        return 'Data fetched!';
      },
    );

    // 执行异步任务
    _controller.runPhase('fetchData');

    // 监听任务完成
    _controller.phaseCompleted('fetchData').listen((result) {
      // 更新UI
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Task completed: ${result.result}'),
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Async Phase Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Waiting for async task to complete...'),
            if (_controller.phaseStatus('fetchData') == PhaseStatus.running) {
              CircularProgressIndicator()
            } else {
              Text('') // 占位,当任务不在运行时不显示进度条
            },
          ],
        ),
      ),
    );
  }
}

在这个示例中,我们完成了以下步骤:

  1. 定义依赖:在 pubspec.yaml 文件中添加了 async_phase 依赖。
  2. 创建应用:创建了一个简单的 Flutter 应用,包含一个 AsyncPhaseDemo 页面。
  3. 初始化状态:在 initState 方法中,使用 AsyncPhaseController 定义了一个名为 fetchData 的异步任务,该任务模拟了一个网络请求(使用 Future.delayed)。
  4. 运行任务:调用 _controller.runPhase('fetchData') 来运行异步任务。
  5. 监听任务完成:使用 _controller.phaseCompleted('fetchData').listen 方法监听任务完成事件,并在任务完成时显示一个 SnackBar。
  6. 显示UI:在 build 方法中,根据任务的状态显示一个进度条或空文本。

这样,你就可以使用 async_phase 插件来管理和显示异步任务的状态了。

回到顶部