Flutter功能未知插件hisma的探索使用

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

Flutter功能未知插件hisma的探索使用

介绍

hisma 是一个用于 Dart 和 Flutter 的声明式分层状态机实现。它松散地遵循了 UML 状态机规范,该规范基于 Harel 的状态图。以下是 hisma 包及其相关包的简要概述:

Package on pub.dev GitHub Description
hisma repo 核心包,用于创建分层状态机。
hisma_extra repo 提供额外类以简化 hisma 的使用。
hisma_console_monitor repo 在控制台监控状态机状态。
hisma_visual_monitor repo 将状态机状态报告给 visma
visma repo 可视化由 hisma_visual_monitor 报告的状态机状态。
hisma_flutter repo 将状态机转换为 Flutter 路由引擎。
fb_auth_hisma repo 使用 hisma 实现的 Firebase 认证状态机。

特性

功能概述

  • 基础
    • 状态
      • OnEntry 和 OnExit 动作
    • 事务
      • 外部和内部转换
      • minInterval 检查
      • 守卫
      • 优先级
      • onAction 动作
      • onError 动作
  • 层次结构
    • 区域
  • 通过层次结构连接状态机
    • 入口点和入口连接器
    • 出口点和出口连接器
  • 历史记录
    • 浅历史
    • 深历史
  • 监控
    • 控制台监控
    • 可视化监控

快速入门

您可以直接开始使用此包,无需任何先决条件。

使用方法

最小状态机声明

让我们从最小的步骤开始:创建一个只有名称定义的状态机。

final machine = StateMachine(
  name: 'minimal',
  initialStateId: null,
  states: {},
  transitions: {},
);

简单状态机

创建一个更实用的状态机:一个灯的状态机。这个典型的例子声明了一个具有两个状态(onoff)的机器,用户可以通过 turnOnturnOff 事件在这两个状态之间切换。

首先创建表示状态、事件和转换的枚举:

enum S { on, off }

enum E { turnOn, turnOff }

enum T { toOn, toOff }

接下来定义一个函数来创建状态机,并使用该函数创建我们的 lightMachine

StateMachine<S, E, T> createLightMachine({
  RegionList<S, E, T>? regions,
}) =>
    StateMachine<S, E, T>(
      name: 'lightMachine',
      events: E.values,
      initialStateId: S.off,
      states: {
        S.off: State(
          etm: {
            E.turnOn: [T.toOn],
          },
          onEntry: Action(
            description: 'Turning off.',
            action: (machine, arg) async => print('OFF'),
          ),
        ),
        S.on: State(
          etm: {
            E.turnOff: [T.toOff],
          },
          regions: regions,
          onEntry: Action(
            description: 'Turning on.',
            action: (machine, arg) async => print('ON'),
          ),
        ),
      },
      transitions: {
        T.toOn: Transition(to: S.on),
        T.toOff: Transition(to: S.off),
      },
    );

final lightMachine = createLightMachine();

运行状态机

创建一个 play 函数来测试状态机:

Future<void> play() async {
  while (true) {
    await Future<void>.delayed(const Duration(seconds: 1));
    await lightMachine.fire(E.turnOn);
    await Future<void>.delayed(const Duration(seconds: 1));
    await lightMachine.fire(E.turnOff);
  }
}

main 函数中启动状态机并调用 play 函数:

Future<void> main() async {
  StateMachine.monitorCreators = [
    (machine) => VisualMonitor(machine),
  ];

  await lightMachine.start();
  play();
}

更多关于转换

外部转换

外部转换是从一个状态到另一个状态的转换。当转换发生时,相应的 onExit 和 onEntry 活动将被执行。

T.toStop: Transition(
  to: S.stop,
  minInterval: const Duration(seconds: 1),
  guard: Guard(
    description: 'If not empty.',
    condition: (machine, arg) async => true,
  ),
  priority: 10,
  onAction: Action(
    description: 'Closing.',
    action: (machine, arg) async => print('Closing'),
  ),
  onError: OnErrorAction(
    description: 'Print error message.',
    action: (machine, onErrorData) async => print(onErrorData.message),
  ),
),

内部转换

内部转换是在响应事件时执行某个动作,但不改变状态。

T.timedOn: InternalTransition(
  onAction: Action(
    description: 'Turn on in 3 sec.',
    action: (machine, arg) async {
      print('Initiating timer to turn on in 3 sec.');
      await Future.delayed(
        const Duration(seconds: 3),
        () {
          print('Fire timedOn.');
          machine.fire(E.turnOn);
        },
      );
    },
  ),
),

复合状态机 - 单个区域

构建一个简单的复合状态机,其中父状态机包含一个子状态机(区域)。

首先定义亮度状态机的状态、事件和转换:

enum S { half, full }

enum E { change }

enum T { toHalf, toFull }

定义亮度状态机:

const brightnessMachineName = 'brightnessMachine';

StateMachine<S, E, T> createBrightnessMachine({
  RegionList<S, E, T>? regions,
}) =>
    StateMachine<S, E, T>(
      name: brightnessMachineName,
      events: E.values,
      initialStateId: S.half,
      states: {
        S.half: State(
          etm: {
            E.change: [T.toFull],
          },
          onEntry: Action(
            description: 'Half light.',
            action: (machine, arg) async => print('HALF'),
          ),
        ),
        S.full: State(
          etm: {
            E.change: [T.toHalf],
          },
          onEntry: Action(
            description: 'Full light.',
            action: (machine, arg) async => print('FULL'),
          ),
        ),
      },
      transitions: {
        T.toFull: Transition(to: S.full),
        T.toHalf: Transition(to: S.half),
      },
    );

将亮度状态机添加到 lightMachine 的区域中:

final lightMachine = createLightMachine(
  regions: [Region(machine: createBrightnessMachine())],
);

创建 play 函数来测试新的两层分层状态机:

Future<void> play() async {
  while (true) {
    await Future<void>.delayed(const Duration(seconds: 1));
    await lightMachine.fire(E.turnOn);

    for (var i = 0; i < 5; i++) {
      await Future<void>.delayed(const Duration(seconds: 1));
      await lightMachine.find<S, E, T>(brightnessMachineName).fire(E.change);
      await Future<void>.delayed(const Duration(seconds: 1));
      await lightMachine.find<S, E, T>(brightnessMachineName).fire(E.change);
    }

    await Future<void>.delayed(const Duration(seconds: 1));
    await lightMachine.fire(E.turnOff);
  }
}

复合状态机 - 多个区域

在同一个状态下添加多个区域。这些区域也可以称为并发区域,因为它们(或更准确地说是与它们对应的状态机)可以同时处于活动状态。

入口和出口点

入口和出口点用于在某些情况下,而不是激活这些机器的 initialStateId 所定义的状态,我们希望另一个状态被激活。此外,从这些机器内部,我们希望某些事件触发父状态机中的事件。

入口连接器和入口点

入口连接器映射定义了在父状态机中某个触发器(由父状态机的状态 id、转换 id 和事件 id 组成的三元组)激活时,需要使用子状态机中的哪个入口点。

Region(
  machine: childMachine,
  entryConnectors: {
    Trigger(source: SP.first, event: EP.e1, transition: TP.toSecond): SC.ep1,
  },
),

出口连接器和出口点

出口连接器映射定义了当子状态机达到某个出口点时,父状态机中应触发的事件。

Region(
  machine: childMachine,
  exitConnectors: {SC.exit: EP.turnOff},
),

历史记录

历史记录允许状态机在重新启动时恢复到其上次活动的状态。

  • 浅历史:仅恢复当前状态机的最后活动状态。
  • 深历史:恢复当前状态机及其所有子状态机的最后活动状态。

完整示例

以下是一个完整的示例,展示了如何使用 hisma 创建一个分层状态机:

import 'package:hisma/hisma.dart';
import 'package:hisma_visual_monitor/visual_monitor.dart';

// 定义状态、事件和转换
enum S { on, off }

enum E { turnOn, turnOff }

enum T { toOn, toOff }

// 创建状态机
StateMachine<S, E, T> createLightMachine({
  RegionList<S, E, T>? regions,
}) =>
    StateMachine<S, E, T>(
      name: 'lightMachine',
      events: E.values,
      initialStateId: S.off,
      states: {
        S.off: State(
          etm: {
            E.turnOn: [T.toOn],
          },
          onEntry: Action(
            description: 'Turning off.',
            action: (machine, arg) async => print('OFF'),
          ),
        ),
        S.on: State(
          etm: {
            E.turnOff: [T.toOff],
          },
          regions: regions,
          onEntry: Action(
            description: 'Turning on.',
            action: (machine, arg) async => print('ON'),
          ),
        ),
      },
      transitions: {
        T.toOn: Transition(to: S.on),
        T.toOff: Transition(to: S.off),
      },
    );

// 创建亮度状态机
enum BrightnessS { half, full }

enum BrightnessE { change }

enum BrightnessT { toHalf, toFull }

const brightnessMachineName = 'brightnessMachine';

StateMachine<BrightnessS, BrightnessE, BrightnessT> createBrightnessMachine({
  RegionList<BrightnessS, BrightnessE, BrightnessT>? regions,
}) =>
    StateMachine<BrightnessS, BrightnessE, BrightnessT>(
      name: brightnessMachineName,
      events: BrightnessE.values,
      initialStateId: BrightnessS.half,
      states: {
        BrightnessS.half: State(
          etm: {
            BrightnessE.change: [BrightnessT.toFull],
          },
          onEntry: Action(
            description: 'Half light.',
            action: (machine, arg) async => print('HALF'),
          ),
        ),
        BrightnessS.full: State(
          etm: {
            BrightnessE.change: [BrightnessT.toHalf],
          },
          onEntry: Action(
            description: 'Full light.',
            action: (machine, arg) async => print('FULL'),
          ),
        ),
      },
      transitions: {
        BrightnessT.toFull: Transition(to: BrightnessS.full),
        BrightnessT.toHalf: Transition(to: BrightnessS.half),
      },
    );

// 创建主状态机
final lightMachine = createLightMachine(
  regions: [Region(machine: createBrightnessMachine())],
);

// 创建 play 函数
Future<void> play() async {
  while (true) {
    await Future<void>.delayed(const Duration(seconds: 1));
    await lightMachine.fire(E.turnOn);

    for (var i = 0; i < 5; i++) {
      await Future<void>.delayed(const Duration(seconds: 1));
      await lightMachine.find<BrightnessS, BrightnessE, BrightnessT>(brightnessMachineName).fire(BrightnessE.change);
      await Future<void>.delayed(const Duration(seconds: 1));
      await lightMachine.find<BrightnessS, BrightnessE, BrightnessT>(brightnessMachineName).fire(BrightnessE.change);
    }

    await Future<void>.delayed(const Duration(seconds: 1));
    await lightMachine.fire(E.turnOff);
  }
}

// 主函数
Future<void> main() async {
  StateMachine.monitorCreators = [
    (machine) => VisualMonitor(machine),
  ];

  await lightMachine.start();
  play();
}

总结

通过上述示例,您可以看到如何使用 hisma 创建和管理分层状态机。hisma 提供了丰富的功能,包括状态、转换、层次结构、入口和出口点以及历史记录等,可以帮助您更好地管理和可视化复杂的状态机逻辑。希望这些示例对您有所帮助!


更多关于Flutter功能未知插件hisma的探索使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter功能未知插件hisma的探索使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在探索和使用Flutter中未知的插件(如hisma)时,理解插件的功能和API是至关重要的。由于hisma并非一个广为人知的Flutter插件,并且我无法直接访问最新的第三方库或特定插件的文档,我将提供一个通用的Flutter插件使用模板,并假设你已经从某个源(比如GitHub、pub.dev或其他可信平台)获取了hisma插件的基本信息和用法。

通常,Flutter插件的使用流程包括以下几个步骤:

  1. pubspec.yaml中添加依赖: 首先,你需要在你的Flutter项目的pubspec.yaml文件中添加hisma插件的依赖。请注意,这里我使用的是假设的依赖名和版本号,你需要根据实际的hisma插件信息替换。

    dependencies:
      flutter:
        sdk: flutter
      hisma: ^x.y.z  # 替换为实际的版本号
    
  2. 运行flutter pub get: 添加依赖后,运行以下命令来安装依赖:

    flutter pub get
    
  3. 导入插件并在代码中使用: 接下来,在你的Dart文件中导入hisma插件,并根据其API文档使用其功能。以下是一个假设的示例,展示了如何导入并使用一个名为Hisma的类(这完全基于假设,因为实际的hisma插件可能有不同的API):

    import 'package:flutter/material.dart';
    import 'package:hisma/hisma.dart';  // 假设hisma插件的主文件是hisma.dart
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      Hisma? hisma;
    
      @override
      void initState() {
        super.initState();
        // 初始化hisma插件,这里假设有一个初始化方法init
        hisma = Hisma();
        hisma!.init();  // 假设init是初始化方法
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Hisma Plugin Demo'),
          ),
          body: Center(
            child: ElevatedButton(
              onPressed: () {
                // 假设hisma插件有一个doSomething方法
                hisma!.doSomething().then((result) {
                  // 处理结果
                  print('Result from hisma: $result');
                }).catchError((error) {
                  // 处理错误
                  print('Error: $error');
                });
              },
              child: Text('Do Something with Hisma'),
            ),
          ),
        );
      }
    
      @override
      void dispose() {
        // 清理资源,如果hisma插件有dispose方法的话
        hisma?.dispose();
        super.dispose();
      }
    }
    

注意

  • 上述代码是一个假设的示例,实际的hisma插件可能有完全不同的API和初始化流程。
  • 在使用任何第三方插件之前,务必查阅其官方文档或源代码,以了解正确的使用方法和API。
  • 如果hisma插件在pub.dev上有页面,通常会有详细的安装和使用指南,以及示例代码。

由于我无法直接访问hisma插件的具体信息,建议你在使用前仔细研究其文档和示例代码,以确保正确集成和使用。

回到顶部