State machine's dontTransition() method
uburoiubu opened this issue · comments
Hi, I really appreciate your implementation of state machine.
I have one question though: you have this method called dontTransition()
which makes the state machine reenter the same state. What would be the way to workaround this and not reenter the same state? Is there something like ignoreEvent()
method?
Thanks.
@uburoiubu Did you want to stay in the same state without emitting a transition?
@zhxnlai, yes, I did.
@uburoiubu I don't think we need an ignoreEvent
method because
- although
dontTransition
returns an identity transition, it can be filtered afterwards.
onTransition {
logger.d("received unexpected event ${validTransition.event}")
val validTransition = it as? StateMachine.Transition.Valid ?: return@onTransition
if (validTransition.from == validTransition.to) {
logger.d("received expected event ${validTransition.event} but did not change state")
return@onTransition
}
logger.d("received expected event ${validTransition.event} and changed state")
// ...
}
ignoreEvent
is less debuggable because you would need to write more code to intercept events
@zhxnlai, thanks. Could you elaborate more on the convenience ofdontTransition()
command? as far as I understood, it is more like reenterThisState()
. Or not?
Suppose I don't write the following declaration:
on<Event.OnConfigChanged> { dontTransition() }
then it is an invalid transition for state graph, but on the other hand, we stay in the same state.
If I write it, I reenter the same state, although I write dontTransition()
. It is a little misleading in terms of naming.
Thanks again.
I had the same reaction and was surprised when dontTransition
ends up causing an identity transition. I eventually ended up doing the filtering suggested above, but fixing things this way did make me wish that StateDefinitionBuilder.on
had some overloads with varying amounts of generic values for the handled events; I have a lot of situations like the following:
state<MyState.SomeState> {
on<Event.InterestingEvent> {
transitionTo(MyState.OtherState)
}
on<Event.NoOpEvent1> {
dontTransition()
}
on<Event.NoOpEvent2> {
dontTransition()
}
on<Event.NoOpEvent3> {
dontTransition()
}
}
where it'd be nice to be able to do:
state<MyState.SomeState> {
on<Event.InterestingEvent> {
transitionTo(MyState.OtherState)
}
on<Event.NoOpEvent1, Event.NoOpEvent2, Event.NoOpEvent3> {
dontTransition()
}
}
I tried to accomplish something like this using Matcher
, but since its constructor is private I couldn't. Maybe there's another way I'm missing?
Actually, I was just looking at Scarlet's usages of the state machine and saw this usage
private fun lifecycleStart() =
any<Event, Event.OnLifecycle.StateChange<*>>().where { state == Lifecycle.State.Started }
which looks like that should make this possible, so I'll play with that a bit.
unfortunately it seems that the dontTransition() method also causes the onEnter
to be called for the state. Haven't found a great way around this yet.
I am with you @ThomasDotCodes, I do have events in my state machine, where I need to execute some code but not transition. This behaviour triggering the onEnter
is making it hard to achieve what I want. I am having to write all the onEnter
code under onTransition
when I detect a state change.