Each state may define an onEnter lambda. The onEnter lambda is called every time the FSM enters the state regardless of how the FSM arrived in that state. The onEnter method saves you from having to duplicate common code for every transition into the state.

    StateMachine.create((g) => g
          ..state<Solid>((b) => b
            ..onEnter((s, e) => print('we are now solid'))
            ..on<OnMelted, Liquid>()

By convention the onEnter builder should be the first one after the state builder.

It is safe to call stateMachine.applyEvent call whilst in onEnter. The transition will be queued and processed once the current transition has been completed.

Nested States

When you have a Nested State the onEnter action becomes a little more complex. With a Nested State we say that when you enter a child state you also enter all ancestor states of that child.

As such when entering a new child state we must call onEnter for each ancestor that is being entered. We start with the ancestor nearest the root of the state tree and call its onEnter method, then the next one down and so on until we reach the child state and call its onEnter.

When moving between any two states with a common ancestor onExit and onEntry methods are called for every ancestor up to but excluding the common ancestor (as we are neither entering nor leaving its state).

Concurrent Region

Concurrent Regions are somewhat less complex than Nested States as each concurrent region has an independent set of states so changing state in one region does not affect the state of the other region. Concurrent States can of course be within Nested States and include Nested states so the normal Nested rules apply.

With a concurrent region, the 'onEnter' method will be called for each state that we transition into and then the above noted nesting rules are applied.

When calling onEnter for each state in a concurrent region, we do not define the order that the onEnter methods will be called.

Last updated