Skip to content

Instantly share code, notes, and snippets.

@sphrak
Last active July 19, 2020 13:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sphrak/f8d86faaf3ca1c99b7d95692e2b1637b to your computer and use it in GitHub Desktop.
Save sphrak/f8d86faaf3ca1c99b7d95692e2b1637b to your computer and use it in GitHub Desktop.
MVI Example 2 -- StateModel
class MainActivity : AppCompatActivity(R.layout.activity_main) {
@Inject
lateinit var viewModel: MainActivityViewModel
private var isInitialised: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
init()
}
private fun init() {
if (!isInitialised) {
lifecycleScope.launch {
viewModel
.state
.collect(::render)
}
viewModel
.send(
MainActivityView.Event.OnViewInitialised
)
isInitialised = true
}
}
private suspend fun render(state: MainActivityView.State): Unit =
when (state.renderEvent) {
MainActivityView.RenderEvent.Idle -> Unit
is MainActivityView.RenderEvent.DisplayText ->
renderDisplayText(text = state.renderEvent.text)
}
private fun renderDisplayText(text: String) {
// render text
}
}
object MainActivityView {
@ExperimentalCoroutinesApi
class StateModel(initialState: State = State()) {
private val _state = MutableStateFlow(initialState)
val state: StateFlow<State> get() = _state
fun setState(newState: State) {
_state.value = newState
}
fun setRenderState(renderEvent: RenderEvent) {
_state.value = _state.value.copy(renderEvent = renderEvent)
}
}
data class State(
val renderEvent: RenderEvent = RenderEvent.Idle
)
sealed class Event {
object OnViewInitialised : Event()
data class OnButtonClicked(val idOfItemClicked: Int) : Event()
}
sealed class RenderEvent {
object Idle : RenderEvent()
data class DisplayText(val text: String) : RenderEvent()
}
}
class MainActivityViewModel @Inject constructor(
private val state: MainActivityView.StateModel,
private val messageOfTheDayRepository: MessageOfTheDayRepository
) {
val state: StateFlow<MainActivityView.State>
get() = stateModel.state
fun send(event: MainActivityView.Event): Unit {
viewModelScope.launch {
reduce(event = event)
}
}
private suspend fun reduce(event: MainActivityView.Event): Unit =
when (event) {
MainActivityView.Event.OnViewInitialised -> onViewInitialisedEvent()
MainActivityView.Event.OnButtonClicked -> onButtonClickedEvent(event.idOfItemClicked)
}
private suspend fun onViewInitialisedEvent() {
val motd: String = withContext(Dispatchers.IO) {
messageOfTheDayRepository.getMOTD()
}
val renderEvent = MainActivityView.RenderEvent.DisplayText(text = motd)
stateModel.setRenderEvent(renderEvent = renderEvent)
}
private fun onButtonClickedEvent(idOfItemClicked: Int) {
// do something to handle click
println("item clicked: $idOfItemClicked")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment