Перейти к содержанию

🗒 Задача

В разработке Android приложений часто используется паттерн MVVM (Model-View-ViewModel) для разделения бизнес-логики и пользовательского интерфейса. ViewModel отвечает за управление состоянием приложения и хранит данные, которые необходимы для отображения на экране.

Предположим, что у нас есть MainScreenViewModel первого экрана приложения, для инициализации которого подгружаются данные с сервера. ViewModel хранит единственное свойство mainScreenState, которое представляет собой объект внутреннего data class MainScreenState.

Состояние экрана включает два свойства: data (загружаемые данные — String) и isLoading (индикатор процесса загрузки, обычно имеет значение по умолчанию false).

Создайте data class для хранения состояния. При изменении состояния загрузки необходимо создать новый объект MainScreenState, скопировав текущее состояние и изменив значение поля isLoading.

Создайте метод loadData() в классе MainScreenViewModel, который будет имитировать процесс загрузки данных с сервера. Этот метод не должен принимать параметры и должен последовательно изменять состояние в следующем порядке:

  • отсутствие данных;

  • загрузка данных;

  • наличие загруженных данных.

❌ Ошибки

✏️ Комментарии

Давай все обернем в общий класс `MainScreenViewModel()`. И внутри ВМ будет встроенный дата класс для хранения стейта
Имитацию процесса загрузки данных предлагаю поместить в loadData(). То есть внутри сначала надо у стейта поменять состояние на isLoading true, затем инициализировать некими данными и одновременно прекратить процесс загрузки.
Делается чуть проще. В параметр copy() сразу передается свойство для изменения в копируемом стейте, таким образом в переменную сохранится объект уже со свойством isLoading = true

Пример:
var state: MainScreenState = MainScreenState()
state = state.copy(isLoading = true)

После этого печатаем промежуточный стейт
println(state)
Состояние экрана (стейт) может быть только одно в текущий конкретный момент. Условно он либо грузится, либо отображает данные. Поэтому подход со списком этих объектов тут точно не нужно использовать.
Если помнишь в уроке про дата классы упоминал про метод копирования объекта (который доступен только для дата классов) [https://kotlinlang.org/docs/data-classes.html#copying](https://kotlinlang.org/docs/data-classes.html#copying)

В задаче помимо сеттинга вью модели на самом деле акцент на применение этого метода (как позже научимся делать в реальном мобильном приложении).

Так вот у нас есть определенное состояние (стейт). Оно уже хранит какие-то загруженные данные для отображения их на экране (data). Если мы создадим новый объект стейта с нужными полями типа sLoading = false, то данные удалятся.

Поэтому применяется метод копирования предыдущего стейта. И по итогу и данные сохраняются, и в новом объекте стейта свойство isLoading (или какое нужно поменять сейчас) будет изменено.

🧾 Решение

class MainScreenViewModel {
    var state: MainScreenState = MainScreenState()

    fun loadData() {
        state = state.copy(isLoading = true)
        println(state)

        val loadedData = "Data from server"
        state = state.copy(data = loadedData, isLoading = false)
        println(state) 
    }

    data class MainScreenState(
        val data: String? = null,
        val isLoading: Boolean = false
    )
}

fun main() {
    val viewModel = MainScreenViewModel()
    println(viewModel.state)

    viewModel.loadData()
}