# 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)
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.tejpratapsingh.com/android-tips/interview/architecture-pattern/mvvm-architecture-pattern.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
