Skip to content
Devrath edited this page Apr 10, 2024 · 10 revisions

Mavericks

  • Mavericks is a MVI-framework

Simplest screen

/** State classes contain all of the data you need to render a screen. */
data class CounterState(val count: Int = 0) : MavericksState

/** ViewModels are where all of your business logic lives. It has a simple lifecycle and is easy to test. */
class CounterViewModel(initialState: CounterState) : MavericksViewModel<CounterState>(initialState) {
    fun incrementCount() = setState { copy(count = count + 1) }
}

/**
 * Fragments in Mavericks are simple and rarely do more than bind your state to views.
 * Mavericks works well with Fragments but you can use it with whatever view architecture you use.
 */
class CounterFragment : Fragment(R.layout.counter_fragment), MavericksView {
    private val viewModel: CounterViewModel by fragmentViewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        counterText.setOnClickListener {
            viewModel.incrementCount()
        }
    }

    override fun invalidate() = withState(viewModel) { state ->
        counterText.text = "Count: ${state.count}"
    }
}

Core Concepts

Mastering Mavericks only requires using three classes

MavericksState

  • This is the first step in creating a Screen by modeling it as a function of state.
  • The Mavericks state doesn't do anything but signal the intention of your class to be used as a state.
  • Ensuring the state class is a data class.
  • Uses only immutable properties.
  • All the properties have a default value so that it can be immediately loaded.
data class UserState(
    val score: Int = 0,
    val previousHighScore: Int = 150,
    val livesLeft: Int = 99,
) : MavericksState
  • You can create derived properties, The derived properties are the properties inside the body of your state class.
data class UserState(
    val score: Int = 0,
    val previousHighScore: Int = 150,
    val livesLeft: Int = 99,
) : MavericksState {
    // Properties inside the body of your state class are "derived".
    val pointsUntilHighScore = (previousHighScore - score).coerceAtLeast(0)
    val isHighScore = score >= previousHighScore
}
  • Placing logic as a derived property like pointsUntilHighScore or isHighScore means that, You can subscribe to changes to just these derived properties, It will never be out of sync with the underlying state.

MavericksViewModel

Clone this wiki locally