Рассмотрим примере применения ViewModel на простом примере:
package com.example.helloapp import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.unit.sp import androidx.lifecycle.ViewModel import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateListOf import androidx.compose.ui.text.input.KeyboardType import androidx.lifecycle.viewmodel.compose.viewModel class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Main() } } } data class User(val name: String, val age: Int) class UserListViewModel: ViewModel() { val users = mutableStateListOf<User>(User("Tom", 39), User("Bob", 43)) var userName by mutableStateOf("") var userAge by mutableStateOf(0) fun addUser(){ users.add(User(userName, userAge)) } fun changeName(value: String){ userName = value } fun changeAge(value: String){ userAge = value.toIntOrNull()?:userAge } fun deleteUser(user: User){ users.remove(user) } } @Composable fun Main(vm: UserListViewModel = viewModel()) { Column { UserData(vm.userName, vm.userAge, changeName = {vm.changeName(it)}, changeAge = {vm.changeAge(it)}, add={vm.addUser()}) UserList(users = vm.users, delete = {vm.deleteUser(it)}) } } @Composable fun UserList(users:List<User>, delete:(User)->Unit) { LazyColumn(Modifier.fillMaxWidth()) { items(users) {u -> Text(u.name, Modifier.padding(start=12.dp), fontSize = 25.sp) Text(u.age.toString(), Modifier.padding(start=12.dp), fontSize = 22.sp) TextButton(onClick = {delete(u)}) { Text("Delete", fontSize = 22.sp) } } } } @Composable fun UserData(userName: String, userAge:Int, changeName:(String)->Unit, changeAge:(String)->Unit, add:()->Unit){ Column{ OutlinedTextField(value = userName, modifier=Modifier.padding(8.dp), label = {Text("Enter a name")}, onValueChange = {changeName(it)}) OutlinedTextField(value = userAge.toString(), modifier=Modifier.padding(8.dp), label = {Text("Enter an age")}, onValueChange = {changeAge(it)}, keyboardOptions = KeyboardOptions(keyboardType= KeyboardType.Number) ) Button(onClick = { add() }, Modifier.padding(8.dp)) { Text("Create", fontSize = 22.sp) } } }
Прежде всего здесь определяется класс User - модель данных, с которыми мы будем работать:
data class User(val name: String, val age: Int)
Данный класс представляет пользователя. Свойство name представляет его имя , а age - возраст.
Для работы с данными определена модель представления UserListViewModel. Она управляет списком пользователей, в который мы можем добавить других пользователей или, наоборот, удалить из него пользователей. Непосредственно сам список пользователей хранится в переменной users. По умолчанию в этот список добавлено 2 объекта:
val users = mutableStateListOf<User>(User("Tom", 39), User("Bob", 43))
Для добавления нового пользователя определяются две переменных - для имени и возраста:
var userName by mutableStateOf("") var userAge by mutableStateOf(0)
Для управления данными также определяется ряд функций:
fun addUser(){ users.add(User(userName, userAge)) } fun changeName(value: String){ userName = value } fun changeAge(value: String){ userAge = value.toIntOrNull()?:userAge } fun deleteUser(user: User){ users.remove(user) }
В функции addUser добавляем нового пользователя, используя переменные name и age. В функции deleteUser получаем удаляемого пользователя и удаляем его из списка. И функции changeName и changeAge предназначены для изменения переменных name и age соответственно. Обратите внимание, что в changeAge передается строка, которую надо преобразоваь в число.
Для создания формы ввода данных нового пользователя определен компонент UserData с двумя текстовыми полями для имени и возраста:
fun UserData(userName: String, userAge:Int, changeName:(String)->Unit, changeAge:(String)->Unit, add:()->Unit){ Column{ OutlinedTextField(value = userName, modifier=Modifier.padding(8.dp), label = {Text("Enter a name")}, onValueChange = {changeName(it)}) OutlinedTextField(value = userAge.toString(), modifier=Modifier.padding(8.dp), label = {Text("Enter an age")}, onValueChange = {changeAge(it)}, keyboardOptions = KeyboardOptions(keyboardType= KeyboardType.Number) ) Button(onClick = { add() }, Modifier.padding(8.dp)) { Text("Create", fontSize = 22.sp) } } }
При изменении введенных данных в текстовых полях будут вызываться функции changeName и changeAge, которые получают введенное значение. А при нажатии на кнопку будет вызываться функция addUser, которая добавит нового пользователя.
Для вывода списка предназначен компонент UserList:
@Composable fun UserList(users:List<User>, delete:(User)->Unit) { LazyColumn(Modifier.fillMaxWidth()) { items(users) {u -> Text(u.name, Modifier.padding(start=12.dp), fontSize = 25.sp) Text(u.age.toString(), Modifier.padding(start=12.dp), fontSize = 22.sp) TextButton(onClick = {delete(u)}) { Text("Delete", fontSize = 22.sp) } } } }
Здесь для каждого пользователя в списке создается пара текстовых меток для вывода имени и возраста с кнопкой удаления, по нажатию на которую будет вызываться функция deleteUser.
И оба этих компонента вызываются в компоненте верхнего уровня Main, который получает ViewModel и передает ее данные в компоненты:
@Composable fun Main(vm: UserListViewModel = viewModel()) { Column { UserData(vm.userName, vm.userAge, changeName = {vm.changeName(it)}, changeAge = {vm.changeAge(it)}, add={vm.addUser()}) UserList(users = vm.users, delete = {vm.deleteUser(it)}) } }
В итоге приложения отобразит список, в который мы сможем добавлять новые данные: