Як обробляти стан у Flutter за допомогою шаблону BLoC

Минулого року я взяв Флаттера, і мушу сказати, що поки що це була надзвичайна подорож. Flutter - це чудова платформа Google для створення високоякісних додатків для Android та iOS.

Як і при побудові майже будь-якої програми, завжди існує необхідність обробляти стан програми. Важливо, щоб управління державою здійснювалося ефективно, щоб уникнути накопичення технічної заборгованості, особливо в міру того, як ваша заявка зростає та ускладнюється.

У Flutter всі компоненти інтерфейсу є віджетами. Починаючи складати ці віджети, щоб створити свою чудову програму, у вас з’явиться дерево глибоко вкладених віджетів. Ці віджети, швидше за все, потребуватимуть обміну станом програми між собою.

У цій статті ми побачимо, як обробляти стан у Flutter за допомогою шаблону BLoC.

Управління державою в Flutter можна досягти кількома різними способами:

Успадкований віджет : він дозволяє розповсюджувати дані до своїх дочірніх віджетів, і віджети відновлюються щоразу, коли змінюється стан програми. Недоліком використання базового класу InheritedWidget є те, що ваш стан остаточний, і це створює проблему, якщо ви хочете змінити свій стан.

Модель із розмахом : це зовнішній пакет, побудований поверх InheritedWidget, і він пропонує дещо кращий спосіб отримати доступ, оновити та змінити стан. Це дозволяє легко передавати Модель даних від батьківського віджету до його нащадків. Крім того, він також перебудовує всіх дітей, які використовують модель, коли модель оновлюється.

Це може спричинити проблему продуктивності, залежно від того, скільки ScopedModelDescendants має модель, оскільки вони відновлюються при оновленні.

Цю проблему можна виправити, розклавши ScopedModel на кілька моделей, щоб отримати детальніші залежності. Встановлення rebuildOnChangeпрапора falseтакож виправляє цю проблему, але це приносить із собою пізнавальне навантаження щодо вирішення, який віджет слід відновити чи ні.

Redux : Так! Як і у випадку з React, існує пакет Redux, який допоможе вам легко створити та використати магазин Redux у Flutter. Як і його аналог JavaScript, зазвичай є кілька рядків зразкового коду та зворотній шлях дій та редукторів .

Введіть шаблон BLoC

Шаблон Business Logic Component (BLoC) - це шаблон, створений Google і оголошений на Google I / O '18. Шаблон BLoC використовує реактивне програмування для обробки потоку даних у програмі.

BLoC є посередником між джерелом даних у вашому додатку (наприклад, відповідь API) та віджетами, які потребують даних. Він отримує потоки подій / даних від джерела, обробляє будь-яку необхідну бізнес-логіку та публікує потоки змін даних у віджетах, які їх цікавлять.

BLoC має два простих компоненти: Мийки та Потоки , обидва з яких забезпечуються StreamController . Ви додаєте потоки подій / даних, що вводяться в раковину, і слухаєте їх як потоки даних, що виводяться через потік .

StreamController можна отримати доступ через ‘dart:async’бібліотеку або як PublishSubject , ReplaySubject або BehaviourSubject через rxdartпакет.

Нижче наведено фрагмент коду, що показує простий BLoC:

import 'dart:async'; // import 'package:rxdart/rxdart.dart'; if you want to make use of PublishSubject, ReplaySubject or BehaviourSubject. // make sure you have rxdart: as a dependency in your pubspec.yaml file to use the above import class CounterBloc { final counterController = StreamController(); // create a StreamController or // final counterController = PublishSubject() or any other rxdart option; Stream get getCount => counterController.stream; // create a getter for our Stream // the rxdart stream controllers returns an Observable instead of a Stream void updateCount() { counterController.sink.add(data); // add whatever data we want into the Sink } void dispose() { counterController.close(); // close our StreamController to avoid memory leak } } final bloc = CounterBloc(); // create an instance of the counter bloc //======= end of CounterBloc file //======= somewhere else in our app import 'counter_bloc.dart'; // import the counter bloc file here @override void dispose() { bloc.dispose(); // call the dispose method to close our StreamController super.dispose(); } ... @override Widget build(BuildContext context) { return StreamBuilder( // Wrap our widget with a StreamBuilder stream: bloc.getCount, // pass our Stream getter here initialData: 0, // provide an initial data builder: (context, snapshot) => Text('${snapshot.data}'), // access the data in our Stream here ); } ...

BLoC - це простий клас Dart. У наведеному вище фрагменті коду ми створили CounterBlocклас і в ньому, StreamControllerякий ми викликали counterController. Ми створили геттер для нашого потоку, який називається getCount, updateCountметод, який додає дані в нашу раковину при disposeвиклику , і метод, щоб закрити наш StreamController.

Щоб отримати доступ до даних у нашому потоці, ми створили StreamBuilderвіджет і передали наш потік до його streamвластивості та отримали доступ до даних у його builderфункції.

Впровадження BLoC

Ми перетворимо зразок програми Flutter за замовчуванням на використання BLoC. Давайте створимо новий додаток Flutter. У вашому терміналі запустіть таку команду:

$ flutter create bloc_counter && cd bloc_counter

Відкрийте додаток у вашому улюбленому редакторі і створити три файли в папці Lib: counter.dart, counter_provider.dartі counter_bloc.dart.

Ми CounterProviderміститиме ціле число та спосіб його збільшення. Додайте до counter_provider.dartфайлу такий код :

class CounterProvider { int count = 0; void increaseCount() => count++; }

Далі ми реалізуємо наш лічильник BLoC. Додайте код нижче у свій counter_block.dartфайл:

У нашому CounterBlocкласі ми використовували частину нашого початкового зразка коду вище. У рядку 7 ми створили інстанцію нашого CounterProviderкласу, а в updateCountметоді ми викликали метод провайдера для збільшення кількості, а потім у рядку 13 передали відлік в наш Sink.

Замініть код у вашому main.dartфайлі на код нижче. У наведеному нижче коді ми просто видалили більшу частину коду лічильника за замовчуванням, який ми перемістимо до нашого counter.dartфайлу. Щоразу, коли incrementCounterметод викликається, ми викликаємо updateCountметод BLoC, який оновлює рахунок і додає його до нашого Sink.

Зараз наш BLoC отримує та передає дані. Ми можемо отримати доступ до цих даних і відобразити їх на екрані через StreamBuilder . Ми обертаємо будь-який віджет, який потребує даних, у віджет StreamBuilder і передаємо йому потік, що містить дані. Додайте до counter.dartфайлу такий код :

У наведеному вище коді ми маємо віджет з виглядів. У нашому класі стану, у рядку 13, ми викликаємо метод dispose нашого блоку, так що контролер потоку може бути закритий при кожному видаленні віджета з дерева.

У рядку 19 ми повертаємо віджет StreamBuilder і рядок 20, передаємо йому геттер для нашого потоку, а також початкові дані в рядку 21. StreamBuilder також має такий, builderякий надає нам доступ до даних через snapshot. У рядку 30 ми отримуємо доступ та відображаємо дані на знімку.

Вперед і запустіть програму, виконавши команду нижче. Переконайтеся, що у вас запущений емулятор.

$ flutter run

Коли ваш додаток запущений, натисніть значок плюса і спостерігайте, як лічильник збільшується з кожним клацанням.

Разом ми змогли реалізувати найпростішу форму BLoC у Flutter. Концепція залишається незмінною незалежно від вашого випадку використання.

Сподіваюся, ця стаття виявилася вам корисною. Будь ласка, робіть і діліться, щоб інші могли знайти цю статтю. Підкажіть мені у Twitter @developia_ з питаннями або для чату.