Использование MVVM во Flutter
Исходя в первую очередь из Kotlin фон, мне было довольно сложно заставить мою голову трепетать в самом начале. Это главным образом потому, что Flutter следует декларативному стилю программирования, тогда как Kotlin следует императивному стилю программирования.
Декларативное программирование фокусируется на том, что программа должна выполнять, а не на том, как это достигается.
По этой причине способ программирования на флаттер становится совершенно другим. Приведу пример. В Kotlin, если нам нужно обновить текст TextView, мы можем легко вызвать метод setText.
textView.text = "New text"
Но обновление текста во Flutter совершенно другое, поскольку оно не позволяет нам обновлять текст текстового поля. Вместо этого мы можем перестроить компонент с обновленным текстовым значением, вызвав setState в StatefulWidget.
setState(() { newText = "New text"; });
Если вы тоже из Kotlin, то, думаю, вы хорошо знакомы с архитектурой MVVM и liveata, где простой код для извлечения и отображения данных из модели просмотра при управлении другим состоянием выглядит так:
private fun observeSkuListResponse() { homeViewModel.skuListResponse.observe(this, Observer { when (it.status) { Status.LOADING -> { binding.loadingLayout.visibility = View.VISIBLE } Status.SUCCESS -> { binding.loadingLayout.visibility = View.GONE // perform other operation } Status.ERROR -> { binding.loadingLayout.visibility = View.GONE binding.errorLayout.visibility = View.VISIBLE } } }) }
Код довольно прост: если ваше состояние находится в состоянии загрузки, вы отображаете только экран загрузки. Если ваш ответ завершен, вы скрываете экран загрузки и отображаете данные. И если в вашем ответе есть ошибка, вы скрываете все другие представления и отображаете сообщение об ошибке.
Поскольку у флаттера нет концепции видимости, мы должны напрямую передать представление, которое мы хотим отобразить на экране, и снова перерисовать компоненты. Для получения состояния мы будем использовать провайдера.
Краткое введение о провайдере
Провайдер используется для управления состоянием во флаттере. Он состоит из 3-х компонентов
- Уведомление об изменениях
- Изменить поставщика уведомлений
- Потребитель
Средство уведомления об изменениях позволяет понять, что такое модель просмотра для Kotlin в архитектуре MVVM. Это центральная точка, которая управляет состоянием экрана. Если состояние внутри него изменяется, он уведомляет фреймворк, чтобы он снова перестроил экран.
ChangeNotifierProvider предоставляет экземпляр ChangeNotifier в представлении.
Consumer - это виджет, который позволяет нам использовать ChangeNotifier.
Поместите своего потребителя чуть выше кода, который должен получить доступ к уведомителю об изменениях. Это потому, что он перестраивает свои дочерние виджеты, когда есть какие-то изменения, и вы не хотите перестраивать весь экран каждый раз, когда есть какие-то изменения.
Теперь перейдем к коду.
ViewModel
Здесь я создал функцию fetchSkuList (), которая извлекает skus из _homeRepo, а затем устанавливает значение в skuListUseCase. Наконец, он уведомляет об изменении данных, вызывая notifyListener ().
Здесь Response - это класс, который отвечает за передачу информации о состоянии данных, то есть о загрузке, завершении или ошибке, в пользовательский интерфейс.
Эти состояния представлены ResponseState, который представляет собой перечисление, состоящее из:
enum ResponseState{ LOADING, COMPLETE, ERROR }
Экран пользовательского интерфейса
На моем домашнем экране, во-первых, я получил данные в initState. Затем в методе сборки я разместил ChangeNotifierProvider и Consumer прямо под панелью приложений, так как я хочу, чтобы остальная часть экрана обновлялась соответствующим образом при изменении состояния данных. После добавления Consumer оператор switch проверяет текущее состояние: Loading, Error или Complete и соответственно обновляет пользовательский интерфейс.
Экран загрузки и экран ошибок - это простой экран, на котором отображается индикатор выполнения и текстовое сообщение.
Экран загрузки
import 'package:flutter/material.dart'; class LoadingScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Center( child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), SizedBox( height: 8, ), Text( 'Loading...', style: TextStyle(fontFamily: 'Roboto'), ) ], ), )); } }
Экран ошибки
import 'package:flutter/material.dart'; class ErrorScreen extends StatelessWidget { final String msg; ErrorScreen(this.msg); @override Widget build(BuildContext context) { return Center( child: Container( child: Text( '$msg', style: TextStyle(fontFamily: 'Roboto'), ))); } }
Вот и все: самый простой способ управлять состоянием с помощью провайдера.
Ознакомьтесь с моим репозиторием на github для получения более подробной информации.
Если статья вам понравилась, не забудьте аплодировать и оставить комментарий. :)