We’re going to see tips on how to create a State Machine and implement it on Jetpack Compose
Why do we want a state machine on Jetpack Compose? Let’s begin from the fundamentals!
Jetpack Compose is the brand new framework launched by Google that can exchange the present XML view system launched a decade in the past. It’s very completely different from the legacy one as a result of we’re transferring from the Crucial Programming strategy to Declarative Programming, the place the UI elements are capabilities, and each argument represents a property or perhaps a state of our element.
The state: that is an important a part of this text as a result of mainly Compose was designed to react to a change of state, because of this our main purpose is to search out one of the best ways to control this state.
Once I say “finest” I imply:
- sustaining this state constant in the course of the execution
- making the code readable/maintainable with out spaghetti code 🍝
- making it testable (please don’t skip this level 😈 )
The aim of this text is to clarify tips on how to implement a State Machine through the use of this library https://github.com/freeletics/FlowRedux, tips on how to combine it with Jetpack Compose and final however not least, tips on how to write checks on it.
Our case of examine can be a small app which permits the consumer to sort a Github username and fetch the associated repositories checklist, so our area layer will expose this Interface:
In any other case from a UI perspective, our app can be composed of a TextField, a affirm Button and a LazyColumn, like this snippet:
Now we have to discover higher glue for the UI and the area layer: a stage machine. My suggestion is to start out fascinated by the states, which set of states will characterize my UI? I’ve considered three of them:
- Content material state: the place mainly the TextField is valorised with the username and the LazyColumn with the checklist of repositories (LazyColumn works like a RecyclerView)
- Loading State: used when the app is making the HTTP request
- Error State: is the case one thing goes unsuitable
Now occasions/actions which might manipulate our state:
- The consumer is typing the username: in compose exists the idea of unidirectional information move (learn extra right here), so we have to persist the TextField’s worth inside our state.
- Verify button tapped: the occasion is triggered when a consumer faucets on the search button.
- Person prompts a retry: triggered by the retry button within the Error State.
If we draw the state machine it must be one thing just like this:
From a code perspective, these could possibly be our States and Actions:
The State Machine
Now the enjoyable half, we’re going to implement the state machine and we have to outline the supported actions for every of those states. FlowRedux will assist us on this iteration.
FlowRedux is a library which lets you create a State Machine the place for every State we are able to declare (in a DSL manner) which actions are supported. Every motion is ready to do logic and manipulate the state in numerous methods:
- override the state with a brand new one
- mutate the state properties with out altering the sort
- maintain the identical state with out adjustments
Have a look at the pattern under.
Principally, we’re making a FlowReduxStateMachine with a state primarily based on GithubState and a set of actions primarily based on the GithubAction, then we have to outline the initialState, which goes to be the preliminary state, in our case is the ContentState (the place enter and repositories are empty).
Now we have to describe the State Machine behaviour contained in the spec , FlowRedux means that you can outline completely different behaviours for any actions primarily based on the present state.
Ranging from the ContentState:
On this state, we’re saying that each time the UI emits:
- GithubAction.TypeOwner we mutate the ContentState with a purpose to persist the consumer’s enter.
- GithubAction.Verify we override it with the LoadingState which accommodates the username typed by the consumer (if it’s not empty, in any other case we don’t do something).
And the Load state?
It’s a bit completely different as a result of we’re utilizing the onEnter operate, this operate is named each time the state transits to Load, and that is good as a result of we are able to name the GithubRepository and get the repositories checklist.
In case we now have successful we override the state with the ContentState in any other case we swap to an Error state, the place mainly we are able to retry the decision:
Find out how to combine the StateMachine on Jetpack Compose
The state machine is prepared, now we have to connect it to our Composable UI. There are numerous choices, I’ve determined to encapsulate the State Machine inside a ViewModel and cross it to the UI.
Principally, I’ve an summary AbsStateViewModel which exposes the state and permits the emitting of the actions through the use of the viewModelScope (as a result of the dispatch methodology of the FlowReduxStateMachine<S, A> is a droop operate).
so I’ve created a GithubViewModel which extends this class:
And at last, I can cross the ViewModel contained in the Composable operate, that is the end result:
Hey! The place are you going? Now your state machine is prepared however you might want to write checks as effectively! It’s fairly easy, given the state’s updates journey on a Kotlin Movement you want a library which lets you take a look at the emitting, I recommend https://github.com/cashapp/turbine which inserts our scopes.
I’ve additionally used https://github.com/mockk/mockk for the mocking and in case you are I wrote an article on it as effectively.
On this take a look at for instance we’re testing the username typing:
on this different one, we’re testing the behaviour within the case in case the API name fails:
FlowRedux is a really cool library, is it the most effective answer? Possibly sure or perhaps no, we love the “it relies upon” sentence, in previous I labored a bit additionally with MVI sample, and my feeling is that it really works roughly in the identical manner however we now have extra management as a result of we are able to simply outline which actions can be found for a selected state and have a greater hierarchy. One other professional is expounded to the declaration, the DSL syntax simplifies the code and makes it extra readable and maintainable.
I hope you might have loved studying this text! Please depart 1/2/tons of 👏 should you preferred it, feedbacks are welcome as effectively!