Flutter信号处理插件signal的使用

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

Flutter信号处理插件signal的使用

简介

“signal” 是一个基于流的状态管理插件,允许在一个通道中管理多个状态。与Bloc结构类似,但当前状态始终是可访问的。通过 ChannelProviderChannelBuilder,可以方便地在Flutter应用中实现复杂的状态管理。

Signal Logo

使用方法

1. 创建通道和信号

首先,定义一个抽象类 MyChannelSignal 继承自 ChannelSignal,然后创建一个 MyChannel 类继承自 StateChannel<MyChannelSignal>。在这个类中,初始化两个状态:CounterStateNotificationState

abstract class MyChannelSignal extends ChannelSignal {}

class MyChannel extends StateChannel<MyChannelSignal> {
  // 定义 CounterState 和 NotificationState
  late CounterState _counterState;
  late NotificationState _notificationState;

  MyChannel() {
    _counterState = CounterState(() => add(CounterStateSignal()));
    _notificationState = NotificationState(() => add(NotificationStateSignal()));
  }

  // 提供对外的访问接口
  CounterState get counterState => _counterState;
  NotificationState get notificationState => _notificationState;

  [@override](/user/override)
  void initState() {
    _counterState.initState();
    _notificationState.initState();
  }

  [@override](/user/override)
  afterInitState() {
    _counterState.afterInitState();
    _notificationState.afterInitState();
  }

  [@override](/user/override)
  Future<void> dispose() async {
    _counterState.dispose();
    _notificationState.dispose();
    super.dispose();
  }
}
2. 创建状态及其信号

接下来,定义两个状态类 CounterStateNotificationState,并为它们创建对应的信号类 CounterStateSignalNotificationStateSignal

// CounterStateSignal
class CounterStateSignal extends MyChannelSignal {}

// CounterState
class CounterState extends BaseState {
  CounterState(void Function() onStateChanged) : super(onStateChanged);

  int _count = 0;
  int get count => _count;

  [@override](/user/override)
  void initState() {
    wait(signal: false);
    _count = 0;
  }

  [@override](/user/override)
  Future<void> afterInitState() async {
    await incrementFuture();
  }

  [@override](/user/override)
  void dispose() {}

  void increment() {
    _count = _count + 1;
    doneSuccess();
  }

  void decrement() {
    _count = _count - 1;
    doneSuccess();
  }

  Future<void> incrementFuture() async {
    try {
      wait();
      await Future<void>.delayed(const Duration(seconds: 5));
      _count = _count + 1;
      doneSuccess();
    } catch (e) {
      doneError(e.toString());
    }
  }

  Future<void> decrementFuture() async {
    try {
      wait();
      await Future<void>.delayed(const Duration(seconds: 1));
      _count = _count - 1;
      doneSuccess();
    } catch (e) {
      doneError(e.toString());
    }
  }
}

// NotificationStateSignal
class NotificationStateSignal extends MyChannelSignal {}

// NotificationState
class NotificationState extends BaseState {
  NotificationState(void Function() onStateChanged) : super(onStateChanged);

  bool _isOpen = false;
  bool get isOpen => _isOpen;

  [@override](/user/override)
  void initState() {
    wait(signal: false);
    _isOpen = false;
  }

  [@override](/user/override)
  Future<void> afterInitState() async => await changeFuture();

  [@override](/user/override)
  void dispose() {}

  void change() {
    _isOpen = !_isOpen;
    doneSuccess();
  }

  Future<void> changeFuture() async {
    try {
      wait();
      await Future<void>.delayed(const Duration(seconds: 1));
      _isOpen = !_isOpen;
      doneSuccess();
    } catch (e) {
      doneError(e.toString());
    }
  }
}
3. 使用 ChannelProvider 提供通道

ChannelProvider 用于创建通道,并将其暴露给其子组件。它管理通道的生命周期。

void main() => runApp(const MyApp());

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ChannelProvider<MyChannel>(
      channel: (context) => MyChannel(),
      child: const MaterialApp(
        debugShowCheckedModeBanner: false,
        home: HomePage(),
      ),
    );
  }
}
4. 使用 ChannelBuilder 构建响应式UI

ChannelBuilder 用于根据通道中广播的信号构建UI。可以通过 condition 参数指定只对特定类型的信号做出反应。

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Center(child: Text('Signal')),
      ),
      body: ListView(
        children: <Widget>[
          const SizedBox(height: 50),
          SizedBox(
            height: 45,
            width: 45,
            child: ChannelBuilder<MyChannel, MyChannelSignal>(
              condition: (channel, signal) => signal is CounterStateSignal,
              builder: (context, channel, _) {
                final state = channel.counterState;

                return Stack(
                  alignment: Alignment.topCenter,
                  children: <Widget>[
                    !state.success
                        ? Text(state.error)
                        : Text(state.count.toString(), style: const TextStyle(fontSize: 25)),
                    if (state.busy) const CircularProgressIndicator(),
                  ],
                );
              },
            ),
          ),
          ChannelBuilder<MyChannel, MyChannelSignal>(
              condition: (channel, signal) => signal is NotificationStateSignal,
              builder: (context, channel, _) {
                final state = channel.notificationState;

                return Stack(
                  alignment: Alignment.topCenter,
                  children: <Widget>[
                    TextButton(
                      onPressed: state.busy ? null : () => state.change(),
                      child: Text(state.isOpen ? 'Notification: On' : 'Notification: Off',
                          style: TextStyle(fontSize: 25, color: state.isOpen ? Colors.green : Colors.red)),
                    ),
                    if (state.busy) const CircularProgressIndicator(),
                  ],
                );
              }),
          const SizedBox(height: 50),
          ChannelBuilder<MyChannel, MyChannelSignal>(
            condition: (channel, signal) => signal is CounterStateSignal || signal is NotificationStateSignal,
            builder: (context, channel, _) {
              final state = channel.counterState;
              return ElevatedButton(
                onPressed: channel.counterState.busy || channel.notificationState.busy ? null : () => state.increment(),
                child: const Text('CounterState: increment'),
              );
            },
          ),
          ElevatedButton(
            onPressed: () => ChannelProvider.of<MyChannel>(context).counterState.decrementFuture(),
            child: const Text('CounterState: decrementFuture'),
          ),
          ElevatedButton(
            onPressed: () => ChannelProvider.of<MyChannel>(context).notificationState.change(),
            child: const Text('NotificationState: change'),
          ),
          ElevatedButton(
            onPressed: () => ChannelProvider.of<MyChannel>(context).notificationState.changeFuture(),
            child: const Text('NotificationState: changeFuture'),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter信号处理插件signal的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter信号处理插件signal的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter项目中使用signal插件来处理信号的基本示例。signal插件允许你监听和处理操作系统级别的信号,这在处理后台任务、管理应用生命周期等方面特别有用。不过,需要注意的是,Flutter的signal插件主要用于Dart VM(如命令行应用),而在Flutter的移动端应用中,信号处理通常是通过平台特定的方式(如iOS的AppDelegate、Android的Activity)来实现的。

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

dependencies:
  flutter:
    sdk: flutter
  signal: ^0.x.x  # 请检查最新版本号并替换

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

接下来,我们编写一个简单的Flutter命令行应用来演示如何使用signal插件。这个示例将监听SIGINT信号(通常通过按下Ctrl+C触发),并在接收到信号时执行一些清理操作。

import 'dart:io';
import 'package:signal/signal.dart';

void main() {
  // 定义一个处理信号的函数
  void handleSignal(int signal) {
    print('Received signal: $signal');
    // 这里可以添加清理资源的代码,比如关闭文件、停止后台服务等
    exit(signal);  // 根据信号退出程序
  }

  // 监听SIGINT信号(Ctrl+C)
  signal(Signal.sigint, handleSignal);

  // 你的应用主逻辑
  print('Flutter signal handling demo.');
  print('Press Ctrl+C to terminate.');

  // 为了保持程序运行,我们可以进入一个无限循环
  while (true) {
    // 这里可以放置你的应用逻辑,比如定期任务等
    sleep(Duration(seconds: 1));  // 休眠一秒,模拟应用正在运行
  }
}

在这个示例中,我们首先导入了必要的包,然后定义了一个处理信号的函数handleSignal。这个函数将在接收到SIGINT信号时被调用,并打印出接收到的信号编号,然后退出程序。我们使用signal(Signal.sigint, handleSignal);来监听SIGINT信号,并将其与我们定义的处理函数关联起来。

最后,为了让程序保持运行,我们进入了一个无限循环,并在循环中添加了一个简单的休眠操作来模拟应用正在运行的状态。

请注意,这个示例仅适用于Dart VM环境(如命令行应用)。在Flutter的移动端应用中,由于操作系统的差异,信号处理的方式会有所不同,通常需要通过平台通道(Platform Channels)与原生代码进行交互来实现。

回到顶部