children… Presenters gain more responsibility Complex logic within the Presenter is more tedious to test The MVP Approach - With Complex View Hierarchy
birthdate: LiveData<Date> = Transformations.map(user) { convertDate(it.birthDate) } x private fun convertDate(date: String) : Date { val dateFormatter = SimpleDateFormat.getDateInstance() return dateFormatter.parse(date) } x
birthdate: LiveData<Date> = Transformations.map(user) { convertDate(it.birthDate) } x private fun convertDate(date: String) : Date { val dateFormatter = SimpleDateFormat.getDateInstance() return dateFormatter.parse(date) } x
many children all interacting with one another, and with their parents Even the ViewModel could get complex pretty quickly We’re using LiveData to handle granular View choreography within the Fragment…
really looked at the changes that the UI goes through Certain transitions of the UI can be grouped together to form states UI can react to those states not even caring what caused those states in the first place
} x object StateA : x State() { x override fun consumeAction(action: Action): State { x return when (action) { x Button1Click -> StateB Button2Click -> StateC } } x } x States and Actions
} x object StateA : x State() { x override fun consumeAction(action: Action): State { x return when (action) { x Button1Click -> StateB Button2Click -> StateC } } x } x A A States and Actions
} x object StateA : x State() { x override fun consumeAction(action: Action): State { x return when (action) { x Button1Click -> StateB Button2Click -> StateC } } x } x A B Button1Click A States and Actions
} x object StateA : x State() { x override fun consumeAction(action: Action): State { x return when (action) { x Button1Click -> StateB Button2Click -> StateC } } x } x Button2Click C States and Actions A B Button1Click A
{ x abstract fun consumeAction(action: Action): State } x data class StateA( override val sideEffect: SideEffect? = null ) : State(sideEffect) { x override fun consumeAction(action: Action): State { x return when (action) { Button1Click -> StateB Button2Click -> StateC(SideEffect.UpdateStore) x } x } x } x States, Actions, & Side Effects
= null) { x abstract fun consumeAction(action: Action): State } x data class StateA( override val sideEffect: SideEffect? = null ) : State(sideEffect) { x override fun consumeAction(action: Action): State { x return when (action) { Button1Click -> StateB Button2Click -> StateC(SideEffect.UpdateStore) x } x } x } x States, Actions, & Side Effects
SideEffect? = null) { x abstract fun consumeAction(action: Action): State } x data class StateA( override val sideEffect: SideEffect? = null ) : State(sideEffect) { x override fun consumeAction(action: Action): State { x return when (action) { Button1Click -> StateB Button2Click -> StateC(SideEffect.UpdateStore) x } x } x } x A B Button1Click A States, Actions, & Side Effects
all UI elements behave predictably - even across hard to test UI interactions - even across configuration changes ViewModels + LiveData + States Offers the flexibility to create UI abstractions
binding, we can reduce the boilerplate of binding ViewModels/LiveData to container or child ViewGroups Taking this further… Custom implementations of LiveData can serve as further abstractions