Post

MVVM Architecture in Kotlin - Counter App

Introduction

  • MVVM stands for Model-View-ViewModel.
  • It is a design pattern that separates the UI from the business logic.
  • It is a variation of the MVC and MVP design patterns.

A simple counter app

The Counter Model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// CounterModel.kt
data class CounterModel(var count: Int)

class CounterRepository {
    private val _counter = CounterModel(0)

    fun getCounter() = _counter

    fun incrementCounter() {
        _counter.count++
    }

    fun decrementCounter() {
        _counter.count--
    }
}
  • The CounterModel data class represents the counter value.
  • The CounterRepository class contains the business logic for the counter app.
  • It has functions to get the counter value, increment the counter, and decrement the counter.

The Counter ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel

class CounterViewModel() : ViewModel() {
    private val _repository:CounterRepository = CounterRepository()
    private val _count = mutableStateOf(_repository.getCounter().count)

    /*val count: Int
        get() = _count*/
    val count: MutableState<Int> = _count

    fun increment() {
        _repository.incrementCounter()
        _count.value = _repository.getCounter().count
    }

    fun decrement() {
        _repository.decrementCounter()
        _count.value = _repository.getCounter().count
    }
}
  • The CounterViewModel class extends the ViewModel class.
  • It contains the UI logic for the counter app.
  • It has a CounterRepository instance to interact with the business logic.
  • It uses a MutableState to hold the count value.
  • It has functions to increment and decrement the count value.

The Counter Screen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Composable
fun CounterApp(viewModel: CounterViewModel) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = "Count: ${viewModel.count.value}",
            fontSize = 24.sp,
            fontWeight = FontWeight.Bold
        )
        // add a space between the text and the buttons
        Spacer(modifier = Modifier.height(16.dp))

        Row {
            Button(onClick = { viewModel.increment() }) {
                Text("Increment")
            }

            Button(onClick = { viewModel.decrement() }) {
                Text("Decrement")
            }
        }

    }
}
  • The CounterApp composable function displays the UI elements for the counter app.
  • It takes a CounterViewModel instance as a parameter.
  • It displays the count value using the Text composable.
  • It has two Button composable elements to increment and decrement the count value.
  • The onClick lambda functions call the increment and decrement functions of the CounterViewModel.

The Main Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val viewModel: CounterViewModel = viewModel()
            KotlinCounterTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    CounterApp(viewModel)

                }
            }
        }
    }
}
  • The MainActivity class is a subclass of ComponentActivity.
  • The onCreate method sets the content of the activity to a CounterApp composable.
  • It creates an instance of the CounterViewModel using the viewModel() function.
  • The CounterApp composable is passed the CounterViewModel instance.

Conclusion

  • The MVVM architecture separates the UI logic from the business logic.
  • In this example, the CounterViewModel class contains the business logic for the counter app.
  • The CounterApp composable function displays the UI elements and interacts with the CounterViewModel.
This post is licensed under CC BY 4.0 by the author.