От сложности к простоте: как использование Compose, MVI и MutableState позволило нам сократить создание лишних сущностей при обращении к БД внутри ВьюМодели

Введение

При создании приложений часто возникает необходимость обращаться к базе данных (БД) из ВьюМоделей (ViewModel) для получения данных и передачи их во Вью (View). Это может вызвать некоторые проблемы, так как по умолчанию ВьюМодели обрабатывают изменения данных через LiveData, которые могут создавать дополнительные сущности, что может стать причиной утечки памяти. В этой статье мы расскажем, как использование Compose, MVI и MutableState позволило нам сократить создание лишних сущностей при обращении к БД внутри ВьюМодели.

Compose

Compose - это фреймворк для разработки пользовательских интерфейсов на языке Kotlin, который позволяет описывать интерфейсы декларативно. Он предоставляет новый подход к созданию пользовательских интерфейсов, который позволяет использовать функциональное программирование и упрощает работу с данными.

MVI

MVI (Model-View-Intent) - это архитектурный паттерн, который помогает упростить и улучшить взаимодействие между Моделью (Model), Вью (View) и Пользовательскими действиями (Intent) в приложении. Этот паттерн позволяет точно определить, где находятся данные, как они взаимодействуют между собой и как они отображаются в пользовательском интерфейсе.

MutableState

MutableState - это класс, который позволяет создавать изменяемые переменные в Compose. Он позволяет изменять значения переменных и автоматически перерисовывать интерфейс, если значение этой переменной изменилось.

Как мы использовали Compose, MVI и MutableState

Наше приложение представляет из себя базу данных с пользователями. Мы хотели реализовать возможность добавления и удаления пользователей в эту базу данных с помощью интерфейса, созданного на Compose.

Мы начали с создания MVI-модели, которая определяет, как данные будут взаимодействовать между собой. Модель содержит MutableState, который содержит список пользователей, полученных из БД.

data class MainState(val users: List<User> = emptyList())

Теперь нам нужно объявить функции, которые будут обрабатывать пользовательские действия. Мы создадим функцию, которая будет загружать пользователей из БД при запуске приложения.

fun loadUsers() {
    viewModelScope.launch {
        val users = userDao.getAll()      
        _state.value = MainState(users)
    }
}

В этой функции мы используем viewModelScope, чтобы гарантировать, что запрос к БД будет выполнен в фоновом потоке. Затем мы обновляем значение MutableState, который содержит список пользователей.

Далее мы создадим функцию для добавления пользователей.

fun addNewUser(user: User) {
    viewModelScope.launch {
        userDao.insert(user)
        val users = userDao.getAll()
        _state.value = MainState(users)
    }
}

Затем мы создадим функцию для удаления пользователей.

fun deleteUser(user: User) {
    viewModelScope.launch {
        userDao.delete(user)
        val users = userDao.getAll()
        _state.value = MainState(users)
    }
}

Во всех трех функциях, мы используем MutableState, чтобы обновить список пользователей в интерфейсе.

Наконец, мы создали Composable, который отображает список пользователей и содержит кнопки для добавления и удаления пользователей.

@Composable
fun UserList(users: List<User>, onAddClicked: () -> Unit, onDeleteClicked: (User) -> Unit) {
    Column {
        users.forEach { user ->
            Text(text = user.name)
            IconButton(onClick = { onDeleteClicked(user) }) {
                Icon(Icons.Default.Delete, contentDescription = "delete")
            }
        }
        FloatingActionButton(onClick = onAddClicked) {
            Icon(Icons.Default.Add, contentDescription = "add")
        }
    }
}

Здесь мы используем функцию пользователя для отображения списка пользователей. Мы также определяем колбэки для кнопок добавления и удаления, которые будут вызываться при нажатии на соответствующие кнопки.

Заключение

С помощью Compose, MVI и MutableState мы смогли создать приложение, где обращение к БД происходит без создания дополнительных сущностей. Мы использовали MVI для определения, как данные взаимодействуют между собой, и MutableState, чтобы изменять значения переменных и автоматически обновлять интерфейс. Compose позволил нам легко описывать пользовательский интерфейс декларативно. Эти технологии помогли нам упростить разработку и создать эффективный и поддерживаемый код.

Смотри также: