Flutter异步通知插件async_notifier的使用

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

Flutter异步通知插件async_notifier的使用

AsyncNotifier 是一个用于处理所有异步状态的 ValueNotifier。它允许监听、通知并管理加载、错误和数据状态,所有这些都集中在一个地方。

使用方法

AsyncNotifier 实质上是一个带有两个新设置器 futurestreamValueNotifier。它的所有状态都被解析为一个 AsyncSnapshot。由于其特性,它可以很容易地与Flutter的原生小部件和类集成,使得使用起来简单直接。

简单示例

import 'package:async_notifier/async_notifier.dart';

void main() {
  // 不需要初始值,默认为 AsyncSnapshot.nothing()
  final counter = AsyncNotifier<int>();

  // 可监听
  counter.addListener(() {
    print("New state: ${counter.snapshot}");
  });

  // 设置 future 或 stream
  counter.future = Future.value(42);
  counter.stream = Stream.fromIterable([1, 2, 3]);

  // 获取快照
  final AsyncSnapshot<int> snapshot = counter.snapshot;

  // 使用扩展检查状态
  snapshot.isLoading;
  snapshot.isReloading;
  snapshot.requireData;
  snapshot.hasData;
  snapshot.hasError;
  snapshot.hasNone;
  snapshot.error;
  snapshot.stackTrace;

  // 控制 future 或 stream
  counter.cancel(); // 对 future 有效
  counter.dispose();

  // 解析状态
  final result = counter.when(
    data: (data) => 'Data $data',
    error: (error, stackTrace) => 'Error $error',
    loading: () => 'Loading',
  );

  // 或者使用 switch 表达式
  final resultSwitch = switch (snapshot) {
    AsyncSnapshot(:var data?) => 'Data $data',
    AsyncSnapshot(:var error?) => 'Error $error', 
    _ => 'Loading',
  };
}

状态管理

你可以直接监听所有 AsyncNotifier 状态,并将其绑定到其他对象。

class TodosNotifier extends ChangeNotifier {
  TodosNotifier() {
    _todos.addListener(notifyListeners);
    fetchTodos();
  }

  final _todos = AsyncNotifier<List<Todo>>();

  AsyncSnapshot<List<Todo>> get todosSnapshot => _todos.snapshot;

  void fetchTodos() {
    _todos.future = _repository.fetchTodos();
  }

  [@override](/user/override)
  void dispose() {
    _todos.dispose();
    super.dispose();
  }
}

消费状态

你可以使用Flutter的原生解决方案如 ListenableBuilder 来消费状态。

class TodoList extends StatelessWidget {
  const TodoList({super.key, required this.todosNotifier});
  final TodosNotifier todosNotifier;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: todosNotifier,
      builder: (context, _) {
        return todosNotifier.snapshot.when(
          loading: () => const CircularProgressIndicator(),
          error: (error, stackTrace) => Text('Error: $error'),
          data: (data) => ListView.builder(
            itemCount: data.length,
            itemBuilder: (context, index) => Text(data[index].title),
          ),
        );
      },
    );
  }
}

使用 provider

class TodoList extends StatelessWidget {
  const TodoList({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    final todosSnapshot = context.watch<TodosNotifier>().snapshot;

    return todosSnapshot.when(
      loading: () => const CircularProgressIndicator(),
      error: (error, stackTrace) => Text('Error: $error'),
      data: (data) => ListView.builder(
        itemCount: todosListenable.value.length,
        itemBuilder: (context, index) => Text(data[index].title),
      ),
    );
  }
}

完整示例 Demo

以下是一个完整的示例,展示了如何使用 AsyncNotifier 来管理书籍列表的状态,并在UI中显示加载、错误和数据状态。

import 'dart:async';
import 'package:async_notifier/async_notifier.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MainApp(notifier: TodosNotifier()));
}

class Book {
  const Book({required this.id, required this.title});
  final String title;
  final int id;

  [@override](/user/override)
  operator ==(Object other) => other is Book && other.id == id;

  [@override](/user/override)
  int get hashCode => id.hashCode;
}

class BookRepository {
  static final _books = {
    const Book(id: 0, title: 'The Book of Spells'),
    const Book(id: 1, title: 'The Darkhold'),
    const Book(id: 2, title: "The Hitchhiker's Guide to the Galaxy"),
    const Book(id: 3, title: 'The Dark Note'),
    const Book(id: 4, title: 'Book of Cagliostro'),
    const Book(id: 5, title: 'Tome of Stilled Tongue'),
  };

  Future<void> saveBooks(List<Book> books) async {
    await Future<void>.delayed(const Duration(seconds: 1));
    _books.clear();
    _books.addAll(books);
  }

  Stream<List<Book>> streamBooks() async* {
    await Future<void>.delayed(const Duration(seconds: 1));
    yield _books.toList();
  }

  Future<List<Book>> getBooks() async {
    await Future<void>.delayed(const Duration(seconds: 1));
    return _books.toList();
  }
}

class TodosNotifier extends ChangeNotifier {
  TodosNotifier() {
    _books.addListener(notifyListeners);
  }

  final _repository = BookRepository();

  final _books = AsyncNotifier<List<Book>>();

  AsyncSnapshot<List<Book>> get snapshot => _books.snapshot
      .whenData((list) => isAscending ? list : list.reversed.toList());

  bool get isAscending => _ascending;
  var _ascending = false;
  StreamSubscription<List<Book>>? _booksSubscription;

  void toggleSort() {
    _ascending = !_ascending;
    notifyListeners();
  }

  void fetchBooks() {
    _books.future = _repository.getBooks();
  }

  void streamBooks() {
    _booksSubscription = _repository.streamBooks().listen(setBooks);
  }

  void setBooks(List<Book> books) {
    _books.future = Future.value(books);
  }

  void addBook(Book book) {
    fetchBooks();
  }

  void removeBook(Book book) {}

  [@override](/user/override)
  void dispose() {
    _books.dispose();
    _booksSubscription?.cancel();
    super.dispose();
  }
}

class MainApp extends StatelessWidget {
  const MainApp({super.key, required this.notifier});

  final TodosNotifier notifier;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('AsyncNotifier'),
          actions: [
            IconButton(
              icon: const Icon(Icons.refresh),
              onPressed: notifier.fetchBooks,
            ),
            IconButton(
              icon: const Icon(Icons.sort),
              onPressed: () => notifier.toggleSort(),
            ),
          ],
        ),
        body: Center(
          child: RefreshIndicator(
            onRefresh: () async => notifier.fetchBooks(),
            child: ListenableBuilder(
              listenable: notifier,
              builder: (context, _) {
                final list = notifier.snapshot.data ?? [];
                if (notifier.snapshot.isLoading) {
                  return const CircularProgressIndicator();
                }
                return ListView.builder(
                  itemCount: list.length,
                  itemBuilder: (context, index) {
                    final book = list[index];
                    return ListTile(
                      title: Text(book.title),
                      trailing: IconButton(
                        icon: const Icon(Icons.delete),
                        onPressed: () => notifier.removeBook(book),
                      ),
                    );
                  },
                );
              },
            ),
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            notifier.addBook(
              const Book(id: 7, title: 'The 7 Wonders'),
            );
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

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

1 回复

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


当然,以下是一个关于如何在Flutter中使用async_notifier插件来实现异步通知的示例代码。async_notifier插件通常用于在后台任务完成时向UI发送通知。

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

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

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

接下来,我们编写一个简单的Flutter应用,展示如何使用async_notifier

1. 创建一个通知服务

首先,我们创建一个服务类,用于处理异步任务并发送通知。

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

class NotificationService {
  final AsyncNotifier<String> notifier = AsyncNotifier<String>();

  Future<void> performAsyncTask() async {
    // 模拟一个耗时任务
    await Future.delayed(Duration(seconds: 3));

    // 任务完成后发送通知
    notifier.notify("Task completed!");
  }
}

2. 在UI中使用通知服务

接下来,我们在UI组件中使用这个服务,并监听通知。

import 'package:flutter/material.dart';
import 'package:async_notifier/async_notifier.dart';
import 'notification_service.dart';  // 假设你将上面的代码保存在这个文件里

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

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

class NotificationScreen extends StatefulWidget {
  @override
  _NotificationScreenState createState() => _NotificationScreenState();
}

class _NotificationScreenState extends State<NotificationScreen> {
  final NotificationService _notificationService = NotificationService();
  String _notificationMessage = "";

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

    // 订阅通知
    _notificationService.notifier.subscribe((message) {
      setState(() {
        _notificationMessage = message;
      });
    });

    // 启动异步任务
    _notificationService.performAsyncTask();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Async Notifier Example"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              "Notification Message:",
              style: TextStyle(fontSize: 18),
            ),
            SizedBox(height: 10),
            Text(
              _notificationMessage,
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}

3. 运行应用

现在,你可以运行这个Flutter应用。当应用启动时,它会启动一个异步任务,并在任务完成后更新UI,显示“Task completed!”消息。

这个示例展示了如何使用async_notifier插件来在Flutter应用中处理异步通知。你可以根据需要扩展这个示例,以处理更复杂的异步任务和通知逻辑。

回到顶部