Как да се справя със състоянието във Flutter, използвайки BLoC модел

Миналата година взех Flutter и трябва да кажа, че досега беше страхотно пътуване. Flutter е страхотната рамка на Google за създаване на висококачествени приложения за Android и iOS.

Както при изграждането на почти всяко приложение, винаги има нужда да се обработва състоянието на приложението. Важно е управлението на държавата да се обработва ефективно, за да се избегне натрупването на технически дълг, особено когато вашето приложение расте и става по-сложно.

Във Flutter всички компоненти на потребителския интерфейс са приспособления. Когато започнете да съставяте тези приспособления, за да създадете страхотното си приложение, ще получите дърво с дълбоко вложени приспособления. Тези приспособления най-вероятно ще трябва да споделят състоянието на приложението помежду си.

В тази статия ще видим как да обработваме състоянието във Flutter, използвайки BLoC шаблона.

Държавното управление във Flutter може да бъде постигнато по няколко различни начина:

Наследено приспособление: Позволява ви да разпространявате данни към неговите дъщерни приспособления и приспособленията се възстановяват, когато има промяна в състоянието на приложението. Недостатъкът на използването на базовия клас InheritedWidget е, че състоянието ви е окончателно и това поражда проблем, ако искате да мутирате състоянието си.

Модел с обхват : Това е външен пакет, изграден върху InheritedWidget и предлага малко по-добър начин за достъп, актуализация и мутация на състояние. Тя ви позволява лесно да предавате модел на данни от родителска джаджа надолу към нейните потомци. В допълнение, той също така възстановява всички деца, които използват модела, когато моделът се актуализира.

Това може да повдигне проблем с производителността, в зависимост от това колко ScopedModelDescendants има един модел, тъй като те се възстановяват, когато има актуализация.

Този проблем може да бъде отстранен чрез декомпозиране на ScopedModel в множество модели, така че да получите по-фини зависимости. Задаването на rebuildOnChangeзнамето falseсъщо решава този проблем, но носи със себе си познавателното натоварване при вземането на решение коя джаджа да бъде възстановена или не.

Redux : Да! Както при React, и тук има пакет Redux, който ви помага лесно да създавате и консумирате магазин Redux във Flutter. Подобно на неговия аналог в JavaScript, обикновено има няколко реда шаблонни кодове и двупосочните действия и редуктори .

Въведете BLoC модел

Шаблонът за бизнес логически компонент (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. Създадохме getter за извикания ни поток getCount, updateCountметод, който добавя данни в нашата мивка при извикване, и disposeметод за затваряне на нашия StreamController.

За достъп до данните в нашия поток създадохме StreamBuilderприспособление и предадохме нашия поток в неговото streamсвойство и получихме достъп до данните в неговата builderфункция.

Внедряване на BLoC

Ще преобразуваме примерното приложение на Flutter по подразбиране, за да използваме BLoC. Нека да продължим и да генерираме ново приложение Flutter. Във вашия терминал изпълнете следната команда:

$ flutter create bloc_counter && cd bloc_counter

Отваряне на приложението в любимия си редактор и ще създаде три файла в папката ИЪ: 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 предадохме броя на нашата мивка.

Заменете кода във вашия main.dartфайл с кода по-долу. В кода по-долу просто премахнахме по-голямата част от брояча по подразбиране, който ще преместим в нашия counter.dartфайл. Всеки път, когато incrementCounterметодът бъде извикан, ние извикваме метода на BLoC, updateCountкойто актуализира броя и го добавя към нашата мивка.

Сега нашият BLoC получава и предава данни. Можем да осъществим достъп до тези данни и да ги покажем на екран чрез StreamBuilder . Обгръщаме каквото и да е приспособление, което се нуждае от данните, в приспособление StreamBuilder и му предаваме потока, съдържащ данните. Добавете следния код към counter.dartфайла:

В горния код имаме приспособление за състояние. В нашия държавен клас, на ред 13, ние извикваме метода на разположение на нашия блок, така че контролерът на потока може да бъде затворен всеки път, когато приспособлението бъде премахнато от дървото.

На ред 19 връщаме приспособление StreamBuilder и ред 20, предаваме му гетера за нашия поток, а също и първоначални данни на ред 21. StreamBuilder има и такъв, builderкойто ни дава достъп до данните чрез a snapshot. На ред 30 имаме достъп и показваме данните в моментната снимка.

Продължете и стартирайте приложението, като изпълните командата по-долу. Уверете се, че работите с емулатор.

$ flutter run

Когато приложението ви работи, щракнете върху иконата плюс и гледайте как броячът се увеличава с всяко щракване.

Заедно успяхме да приложим най-простата форма на BLoC във Flutter. Концепцията остава същата, независимо от случая на употреба.

Надявам се, че тази статия ви е била полезна. Моля, правете и споделяйте, за да могат другите да намерят тази статия. Насочете ме в Twitter @developia_ с въпроси или за чат.