> For the complete documentation index, see [llms.txt](https://notes.tejpratapsingh.com/android-tips/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://notes.tejpratapsingh.com/android-tips/interview/architecture-pattern/mvvm-architecture-pattern.md).

# MVVM Architecture Pattern

MVVM is an architectural pattern that separates the user interface development from the business logic and data model. It was introduced by Microsoft architects to simplify event-driven programming of user interfaces.

**Core Components:**

1. **Model**
   * Represents the data and business logic
   * Contains the application's data and rules
   * Independent of the user interface
   * Manages data operations, storage, and retrieval
   * Typically includes data models, network calls, and data manipulation logic
2. **View**
   * Represents the user interface
   * Displays data to the user
   * Handles user interactions
   * Observes changes in the ViewModel
   * Passive and doesn't contain complex logic
3. **ViewModel**
   * Acts as a bridge between Model and View
   * Transforms Model data for display
   * Handles UI-related logic
   * Exposes data and commands to the View
   * Contains presentation logic
   * Uses data binding to update the View

**Key Characteristics:**

* **Data Binding**: Automatically synchronizes data between View and ViewModel
* **Reactive Programming**: Often uses observables and reactive streams
* **Separation of Concerns**: Clear separation of UI, logic, and data layers
* **Testability**: Easy to unit test due to clear component responsibilities

**How MVVM Works:**

1. User interacts with the View
2. View sends the action to ViewModel
3. ViewModel processes the action
4. ViewModel interacts with the Model to fetch/update data
5. Model returns data to ViewModel
6. ViewModel transforms and prepares data
7. View is automatically updated through data binding

**Advantages:**

* Improved separation of concerns
* Enhanced testability
* Easier maintenance
* Supports complex user interfaces
* Facilitates parallel development
* Reduces boilerplate code
* Supports reactive programming paradigms

### Class Diagram:

{% @mermaid/diagram content="classDiagram
class Model {
<<interface>>
+fetchData()
+saveData()
+deleteData()
+observeDataChanges()
}

```
class View {
    <<interface>>
    +render()
    +bindViewModel()
    +handleUserInteraction()
    +updateUI()
}

class ViewModel {
    <<interface>>
    +loadData()
    +transformData()
    +processUserAction()
    +getObservableData()
}

class ConcreteModel {
    -dataSource: DataSource
    -database: Database
    +fetchData()
    +saveData()
    +deleteData()
    +observeDataChanges()
}

class ConcreteView {
    -viewModelBinding: ViewModel
    -uiComponents
    +render()
    +bindViewModel()
    +handleUserInteraction()
    +updateUI()
}

class ConcreteViewModel {
    -model: Model
    -dataState: ObservableState
    +loadData()
    +transformData()
    +processUserAction()
    +getObservableData()
}

note for ConcreteViewModel "Transforms Model data\nfor View presentation"

ViewModel <|-- ConcreteViewModel
Model <|-- ConcreteModel
View <|-- ConcreteView

ConcreteViewModel --> Model: retrieves data
ConcreteView --> ViewModel: binds to
ConcreteViewModel ..> View: updates
ConcreteView ..> ViewModel: notifies actions" %}
```

### Code:

```kotlin
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.runBlocking

// Data Model
data class User(
    val id: String,
    val name: String,
    val email: String
)

// Model Interface
interface UserModel {
    fun fetchUsers(): List<User>
    fun addUser(user: User)
    fun deleteUser(userId: String)
    fun observeDataChanges(): Flow<List<User>>
}

// View Interface
interface UserView {
    fun render(users: List<User>)
    fun showError(message: String)
    fun handleUserInteraction()
}

// ViewModel Interface
interface UserViewModel {
    val usersState: StateFlow<List<User>>
    fun loadUsers()
    fun addNewUser(name: String, email: String)
    fun deleteUser(userId: String)
}

// Concrete Model Implementation
class InMemoryUserModel : UserModel {
    private val users = mutableListOf(
        User("1", "John Doe", "john@example.com"),
        User("2", "Jane Smith", "jane@example.com")
    )

    override fun fetchUsers(): List<User> = users.toList()

    override fun addUser(user: User) {
        users.add(user)
    }

    override fun deleteUser(userId: String) {
        users.removeIf { it.id == userId }
    }

    override fun observeDataChanges(): Flow<List<User>> {
        // In a real-world scenario, this would be a more complex observable mechanism
        return MutableStateFlow(users)
    }
}

// Concrete ViewModel Implementation
class UserManagementViewModel(private val model: UserModel) : UserViewModel {
    private val _usersState = MutableStateFlow<List<User>>(emptyList())
    override val usersState: StateFlow<List<User>> = _usersState.asStateFlow()

    override fun loadUsers() {
        // In a real app, this would likely be an asynchronous operation
        val users = model.fetchUsers()
        _usersState.value = users
    }

    override fun addNewUser(name: String, email: String) {
        val newUser = User(
            id = (usersState.value.size + 1).toString(),
            name = name,
            email = email
        )
        model.addUser(newUser)
        _usersState.update { currentUsers -> currentUsers + newUser }
    }

    override fun deleteUser(userId: String) {
        model.deleteUser(userId)
        _usersState.update { currentUsers -> 
            currentUsers.filter { it.id != userId }
        }
    }
}

// Concrete View Implementation (Console-based for demonstration)
class ConsoleUserView(private val viewModel: UserViewModel) : UserView {
    override fun render(users: List<User>) {
        println("\n--- Current Users ---")
        users.forEach { user ->
            println("ID: ${user.id}, Name: ${user.name}, Email: ${user.email}")
        }
    }

    override fun showError(message: String) {
        println("Error: $message")
    }

    override fun handleUserInteraction() {
        while (true) {
            println("\nChoose an action:")
            println("1. View Users")
            println("2. Add User")
            println("3. Delete User")
            println("4. Exit")
            print("Enter your choice: ")

            when (readLine()?.trim()) {
                "1" -> {
                    // Render current users
                    render(viewModel.usersState.value)
                }
                "2" -> {
                    // Add user
                    print("Enter user name: ")
                    val name = readLine() ?: return
                    print("Enter user email: ")
                    val email = readLine() ?: return
                    viewModel.addNewUser(name, email)
                }
                "3" -> {
                    // Delete user
                    print("Enter user ID to delete: ")
                    val userId = readLine() ?: return
                    viewModel.deleteUser(userId)
                }
                "4" -> {
                    println("Exiting...")
                    return
                }
                else -> showError("Invalid choice")
            }
        }
    }
}

// MVVM Application Runner
class MVVMUserManagementApp {
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            // Create MVVM components
            val model = InMemoryUserModel()
            val viewModel = UserManagementViewModel(model)
            val view = ConsoleUserView(viewModel)

            // Initial load of users
            viewModel.loadUsers()

            // Start user interaction
            view.handleUserInteraction()
        }
    }
}

// Bonus: Extension function to observe StateFlow (simulating reactive behavior)
fun <T> StateFlow<T>.observe(action: (T) -> Unit) {
    runBlocking {
        action(value)
    }
}
```
