Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is something wrong with my state machine? #25

Open
Shrikant-B opened this issue Dec 2, 2019 · 2 comments
Open

Is something wrong with my state machine? #25

Shrikant-B opened this issue Dec 2, 2019 · 2 comments

Comments

@Shrikant-B
Copy link

Hi, amazing library. I'm trying to implement it in my own project.

These are my states

sealed class State {
    object Loading : State()
    class Success(val response: SomeDataClass) : State()
    class Failure(val exception: Exception) : State()
}

These are the events:

sealed class Event {
    class OnApiSuccess(val response: SomeDataClass) : Event()
    class OnApiFailure(val exception: Exception) : Event()
}

Finally this is the side effect:

sealed class SideEffect {
    object AfterApiSuccess : SideEffect()
    object AfterApiFailure : SideEffect()
}

This is the implementation of state machine:

val stateMachine = StateMachine.create<State, Event, SideEffect> {
    initialState(State.Loading)
    state<State.Loading> {
        on<Event.OnApiSuccess> {
            transitionTo(State.Success(it.response), SideEffect.AfterApiSuccess)
        }
        on<Event.OnApiFailure> {
            transitionTo(State.Failure(it.exception), SideEffect.AfterApiFailure)
        }
    }
    state<State.Success> { }
    state<State.Failure> { }

    onTransition {
        if (it is StateMachine.Transition.Valid) {
            when (it.sideEffect) {
                SideEffect.AfterApiSuccess ->
                    Log.e("StateMachine", "Current State is : ${it.toState.javaClass.simpleName}")
                SideEffect.AfterApiFailure ->
                    Log.e("StateMachine", "Current State is : ${it.toState.javaClass.simpleName}")
            }
        } else if (it is StateMachine.Transition.Invalid) {
            Log.e("StateMachine", "Something went wrong")
        }
    }
}

I have a MutableLiveData in my viewmodel which observes State
val stateObserver: MutableLiveData<State> = MutableLiveData()
to which I'm posting value as
stateObserver.postValue(stateMachine.transition(Event.OnApiSuccess(response)).fromState)
or stateObserver.postValue(stateMachine.transition(Event.OnApiFailure(exception)).fromState)

And my implementation of LiveData observer is as below:

someViewModel.stateObserver.observe(this, Observer { state ->
            when (state) {
                is State.Loading -> {
                    progress.visibility = View.VISIBLE
                    list.visibility = View.GONE
                    error.visibility = View.GONE
                }
                is State.Success -> {
                    progress.visibility = View.GONE
                    list.visibility = View.VISIBLE
                    error.visibility = View.GONE
                    Log.e("TAG", "Response is :${state.response.results}")
                }
                is State.Failure -> {
                    progress.visibility = View.GONE
                    list.visibility = View.GONE
                    error.visibility = View.VISIBLE
                    Log.e("TAG", "Error is :${state.exception.message}")
                }
            }
        })

I don't what is I'm doing wrong but my app is getting stuck on loading. Help is much appreciated. Thanks.

@lfernandosp
Copy link
Collaborator

Hi @Shrikant-B,

By looking at your code, I can see you're posting transition.fromState to the MutableLiveData. That means it would never emit the terminal states you defined (Success or Failure) unless you postValue the toState part of the transition instead.

Also, you're not actually posting the initial state (Loading) as the ViewModel gets initialized.
I hope this helps.

@Shrikant-B
Copy link
Author

@lfernandosp Thanks for you suggestion, it did helped me with my issue.
So, I changed my LiveData from MutableLiveData<State> to MutableLiveData<StateMachine.Transition<State, Event, SideEffect>>() that gives me Transition with ToState & SideEffect.

I have statemachine as below:

val stateMachine = StateMachine.create<State, Event, SideEffect> {
        initialState(State.Idle)
        state<State.Idle> { onEnter { dontTransition(SideEffect.OnIdle) } }
        onTransition {
            if (it is StateMachine.Transition.Valid) {
                when (it.sideEffect) {
                    is SideEffect.OnIdle -> {

                    }
                }
            } else {
                Log.e("StateMachine", "Invalid transition")
            }
        }
    }

As stateMachine.transition() requires Event to get Transition. How do I consume Transition from onEnter dontTransition?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants