You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+123-4Lines changed: 123 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -12,8 +12,127 @@
12
12
13
13
This project started as a library module in one of my personal projects, but I decided to open source it and add more features for general use. Hope you like!
First, declare your `Action`s and `State`s. They **must** implement `HAL.Action` and `HAL.State` respectively.
20
+
21
+
```kotlin
22
+
sealedclassMyAction : HAL.Action {
23
+
24
+
object LoadPosts : MyAction()
25
+
26
+
data classAddPost(valpost:Post) : MyAction()
27
+
}
28
+
29
+
sealedclassMyState : HAL.State {
30
+
31
+
object Init : MyState()
32
+
33
+
object Loading : MyState()
34
+
35
+
data classPostsLoaded(valposts:List<Post>) : MyState()
36
+
37
+
data classError(valmessage:String) : MyState()
38
+
}
39
+
```
40
+
41
+
Next, implement the `HAL.StateMachine<YourAction, YourState>` interface in your `ViewModel`, `Presenter`, `Controller` or similar.
42
+
43
+
The `HAL` class receives the following parameters:
44
+
* A [`CoroutineScope`](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/) (tip: use the [built in viewModelScope](https://developer.android.com/topic/libraries/architecture/coroutines#viewmodelscope))
45
+
* A initial state
46
+
* A reducer function, `suspend (action: A, transitionTo: (S) -> Unit) -> Unit`, where:
47
+
-`suspend`: the reducer runs inside a coroutine scope on a [default dispatcher](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/), so you can run IO and other complex tasks without worrying about block the Main Thread
48
+
-`action: A`: the action emitted to the state machine
49
+
-`transitionTo: (S) -> Unit`: the function responsible for changing the state
50
+
51
+
You should handle all actions inside the reducer function. Call `transitionTo()` whenever you need to change the state (it can be called multiple times).
overrideval hal by HAL(viewModelScope, MyState.Init) { action, transitionTo ->
58
+
when (action) {
59
+
isMyAction.LoadPosts-> {
60
+
transitionTo(MyState.Loading)
61
+
62
+
try {
63
+
// You can run suspend functions
64
+
val posts = postRepository.getPosts()
65
+
// And emit multiple states per action
66
+
transitionTo(MyState.PostsLoaded(posts))
67
+
} catch(e:Exception) {
68
+
transitionTo(MyState.Error("Ops, something went wrong."))
69
+
}
70
+
}
71
+
72
+
isMyAction.AddPost-> {
73
+
/* Handle action */
74
+
}
75
+
}
76
+
}
77
+
}
78
+
```
79
+
80
+
Finally, inside your view class (`Activity`, `Fragment` or similar) you can emit actions to your state machine and observe state changes.
81
+
82
+
If you want to use a [built in LiveData state observer](https://github.com/adrielcafe/HAL/blob/master/hal-livedata/src/main/kotlin/cafe/adriel/hal/livedata/observer/LiveDataStateObserver.kt), just pass your `LifecycleOwner` to `viewModel.observeState()`, otherwise HAL will use a default [callback-based state observer](https://github.com/adrielcafe/HAL/blob/master/hal-core/src/main/kotlin/cafe/adriel/hal/observer/CallbackStateObserver.kt) (which is best suited for JVM-only applications).
83
+
84
+
```kotlin
85
+
classMyActivity : AppCompatActivity() {
86
+
87
+
privateval viewModel by viewModels<MyViewModel>()
88
+
89
+
overridefunonCreate(savedInstanceState:Bundle?) {
90
+
91
+
// Easily emit actions to your State Machine
92
+
loadPostsBt.setOnClickListener {
93
+
viewModel +MyState.LoadPosts
94
+
}
95
+
96
+
// Observe and handle state changes backed by a LiveData
97
+
viewModel.observeState(this) { state ->
98
+
when (state) {
99
+
isMyState.Init-> showWelcomeMessage()
100
+
101
+
isMyState.Loading-> showLoading()
102
+
103
+
isMyState.PostsLoaded-> showPosts(state.posts)
104
+
105
+
isMyState.Error-> showError(state.message)
106
+
}
107
+
}
108
+
}
109
+
}
110
+
```
111
+
112
+
### Custom StateObserver
113
+
114
+
If needed, you can easily create your custom state observers by just implementing the `StateObserver<State>` interface:
115
+
116
+
```kotlin
117
+
classMyCustomStateObserver<S:HAL.State>(
118
+
privatevalmyCustomParam:SomeCoolClass,
119
+
overridevalobserver: (S) ->Unit
120
+
) : StateObserver<S> {
121
+
122
+
overridefuntransitionTo(newState:S) {
123
+
// Do any kind of operation and call `observer(newState)` in the end
124
+
// IMPORTANT: this method runs on the Main Thread!
125
+
}
126
+
}
127
+
```
128
+
129
+
And to use, just create an instance of it and pass to `observeState()` function:
130
+
131
+
```kotlin
132
+
viewModel.observeState(MyCustomStateObserver(myCustomParam) { state ->
133
+
// Handle state
134
+
})
135
+
```
17
136
18
137
## Import to your project
19
138
1. Add the JitPack repository in your root build.gradle at the end of repositories:
@@ -40,6 +159,6 @@ Current version: [![JitPack](https://img.shields.io/jitpack/v/github/adrielcafe/
0 commit comments