MVI in potato’s way

YE MON KYAW
Arpalar Tech
Published in
6 min readApr 2, 2023

Rome wasn’t built in a day”, I think all of us already hear this word is often used to remind us of the amount of time and effort it takes to create something great.

I mentioned the above words because I wanna give support to new joiners for our native mobile development. We are so lucky because we become developers at an early stage so we don’t have a lot of things to choose from but new joiners are not.

But currently, there are a lot of frameworks, libraries, and architecture to follow. Even if you are already familiar with MVP and MVVM, you should also know about MVI and also a lot of things to learn in a limited time.

TLDR Actually this is not really about MVI architecture I added this keyword to boots my article

I am writing this article because I saw a lot of talented new joiners in our industries who do not satisfy themself in terms of technology so they are trying to learn new things every day. So they do the one mistake as I did before which is we only care to finish rather than why and how its works behind. I wanna suggest don’t wanna go fast in the early stage always remember “Rome wasn’t built in a day”.

Lets me stop my bullshit now, let's go to the explanation about how I learn MVI in my potato’s ways.

MVI stands for Model-View-Intent, which is an architectural pattern used in software development to separate the different components of an application into distinct roles.

In MVI, the Model represents the state of the application and the business logic behind it. The View is responsible for rendering the UI and receiving user inputs, while the Intent represents the user’s actions or intentions.

Here’s a simple example of how MVI can be applied in the context of a student management system:

Model: The model consists of the data related to a student, such as their name, age, and grade.

View: The view is responsible for displaying the student’s information on the screen and allowing the user to interact with it. For example, the user might be able to view a list of students, add a new student, or edit an existing student’s information.

Intent: The intent represents the user’s actions or intentions, such as adding a new student to the system or updating an existing student’s information.

So I think you understand what is MVI by reading my article right? How can be even though I don’t understand which is MVI by reading this? Just kidding let me explain to you with a detailed example so you will be more understanding about MVI.

First, define the data model for a student as a Kotlin data class. We then define the state of the application as an AppState data class, which contains a list of students.

// Define the data model for a student
//Data Model for Student
data class Student(val name: String, val age: Int, val grade: String)

// let assume currently as Data Model
data class AppState(val students: List<Student>)

In this class, the Student is for holding student data, which is for AppState. AppState is for storing the Application State which you will see in detail later. So let's create the Intent to handle the user action below

// Define the actions that the user can perform
sealed class UserIntent {
data class AddStudent(val student: Student) : UserIntent()
data class EditStudent(val student: Student) : UserIntent()
data class DeleteStudent(val student: Student) : UserIntent()
}

In the above example, we already added Model and Intent, so we need V to complete the MVI. let me the view for Students to handle user actions and to show student data.

// Define the UI component to display the list of students 
// and handle user inputs
class StudentListView {

fun render(state: AppState) {
// Render the list of students on the screen
}

fun handleUserInput(intent: UserIntent) {
// Pass the user intent to the presenter
// to update the state of the application
}
}

Tada! congratulations now finish the MVI but you will see our Model, View, and Intent are not connected to each other so we can’t do anything with this architecture. so make this architecture useful and connected.

To implement MVI, we would first define the data model for a student and create a separate class to manage the state of the application based on the data model.

Next, we would create the UI elements (views) to display the student’s information and handle user inputs, and finally, we would define the intents that the user can perform and the corresponding actions that the application should take in response to those intents. So let me refactor the above code as follow :

// Define the data model for a student
data class Student(val name: String, val age: Int, val grade: String)

// Define the state of the application
data class AppState(val students: List<Student>)

// Define the actions that the user can perform
sealed class UserIntent {
data class AddStudent(val student: Student) : UserIntent()
data class EditStudent(val student: Student) : UserIntent()
data class DeleteStudent(val student: Student) : UserIntent()
}

// Define the reducer function to update the state of the
// application based on user intents
// Note that this is not related with React-redux
fun reduce(state: AppState, intent: UserIntent): AppState {
return when (intent) {
is UserIntent.AddStudent -> {
state.copy(students = state.students + intent.student)
}
is UserIntent.EditStudent -> {
state.copy(students = state.students.map {
if (it.name == intent.student.name)
intent.student else it })
}
is UserIntent.DeleteStudent -> {
state.copy(students = state.students.filterNot {
it.name == intent.student.name })
}
}
}

// Define the UI component to display the list of
// students and handle user inputs
class StudentListView {
lateinit var presenter: StudentListPresenter

fun render(state: AppState) {
// Render the list of students on the screen
}

fun handleUserInput(intent: UserIntent) {
// Pass the user intent to the presenter to update
// the state of the application
presenter.handleUserIntent(intent)
}
}

// Define the presenter to handle user inputs and
// update the state of the application
class StudentListPresenter(private val reducer: (AppState, UserIntent)
-> AppState) {
lateinit var view: StudentListView
var state = AppState(emptyList())

fun handleUserIntent(intent: UserIntent) {
state = reducer(state, intent)
view.render(state)
}
}

// Usage example
fun main() {
val presenter = StudentListPresenter(::reduce)
val view = StudentListView()
presenter.view = view
view.presenter = presenter

val newStudent = Student("Ye Mon", 18, "F-")
view.handleUserInput(UserIntent.AddStudent(newStudent))

val updatedStudent = Student("Nyan", 19, "A+")
view.handleUserInput(UserIntent.EditStudent(updatedStudent))

val deletedStudent = Student("Thet", 20, "A")
view.handleUserInput(UserIntent.DeleteStudent(deletedStudent))
}

we define the actions that the user can perform as sealed classes that extend the UserIntent interface. We also define a reducer function that takes the current state of the application and user intent as input and returns a new state based on the intent.

We then define the UI component as a StudentListView class that renders the list of students on the screen and handles user inputs. We also define a StudentListPresenter class that handles user inputs and updates the state of the application by calling the reducer function.

Finally, in the usage example, we create a new instance of the presenter and the view and connect them to each other. We then simulate user inputs by adding a new student, editing an existing student, and deleting a student. The presenter updates the state of the application based on the user inputs, and the view renders the updated list of students on the screen.

I hope you will understand how we can implement MVI in our own way without needing for Android studio and MVI is not only for android.

Thank you for taking the time to read this article. I hope that my writing has been informative and thought-provoking.

Bonus:https://gist.github.com/indexer/ae67e67eccd82d5ecaa05e9f64187884

--

--

YE MON KYAW
Arpalar Tech

Software Engineer who write code in Kotlin / Android