machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Понимание провайдера на диаграммах. Часть 2. Основные провайдеры

Дата публикации Oct 3, 2019

Эта статья является второй в серии из трех частей, в которой описывается архитектура флаттера.пакет провайдераи иллюстрирует эту архитектуру в диаграммах. Предполагается, что читатель прочитал первую статью,Часть 1. Предоставление ценностей, Эта вторая статья знакомит с основными видами провайдеров. Смотрите такжеЧасть 3: Архитектура,

пакет провайдераотличается гибкостью поддержки различных источников состояния. Он имеет множество провайдеров для работы с различными источниками, и даже возможно разработать свой собственный специализированный провайдер. Вы можете выбрать поставщика, обладающего необходимой вам эффективностью и желаемой экономикой выражения. Теперь, когда вы знакомы с тем, как провайдеры предоставляют значения и перестраивают иждивенцев, давайте разберемся с основными видами провайдеров.

Государственные источники и их провайдеры

«Государство» - это не что иное, как ценность. Если мы собираемся перестраивать виджеты об изменениях состояния, нам нужно что-то, что сообщает об изменениях в значениях состояния. В пакете провайдера нет термина для объектов, которые делают это, поэтому мы будем называть их «источниками состояний». Таким образом, источником состояний является объект, который сообщает об изменениях состояния. Источники состояния включают потоки, фьючерсы и экземпляры Listenable, среди прочего. Пакет провайдера включает в себя множество провайдеров, специализирующихся на подписке на различные виды государственных источников.

Следующая диаграмма в общих чертах иллюстрирует процесс восстановления зависимых виджетов, когда источник состояния сообщает об изменении состояния:

Диаграмма показывает четыре виджета, которые зависят от значения состояния. Все иждивенцы сначала строятся на начальном состоянии. Если источник состояния не предоставил значение состояния ко времени этой первой сборки, поставщик передает зависимостям заданное приложением значение начального состояния по умолчанию. Только три зависимости на этой диаграмме впоследствии перестраиваются при изменении состояния.

Процесс восстановления иждивенцев начинается с изменения состояния следующим образом:

  1. Что-то вызывает новое состояние в источнике состояний, такое как внешнее событие, ускоряющее изменение, или внешний объект, отправляющий новое значение состояния. Например, вышеупомянутая зависимость, которая не перестраивается, может представлять кнопку, нажатие которой вызывает изменение состояния.
  2. Источник состояния сообщает провайдеру, что состояние изменилось. Это также может привести к тому, что поставщик получит новое значение состояния из источника состояния в зависимости от типа источника состояния. Поставщик с помощью своего внутреннего InheritedWidget отмечает создание зависимых виджетов, которые прослушивают изменения в значении поставщика.
  3. Среда Flutter перестраивает зависимые, ранее помеченные для построения, в процессе получения нового значения состояния, как объяснено ранее.

Давайте сделаем это более конкретным, изучив основные виды поставщиков.

Основные виды провайдеров

Различные поставщики по-разному взаимодействуют с источниками состояния, чтобы информировать своих иждивенцев об изменениях состояния. Изучив основные виды поставщиков, мы наконец-то сможем понять всю диаграмму архитектуры.

StreamProvider

StreamProviderполучает события отручейи предоставляет эти события своим зависимым виджетам в качестве значений, представляющих состояние. Используйте провайдера типаStreamProvider<T>получить значения типаTизStream<T>,

Говорят, что StreamProvider «подписывается» на поток для получения событий, которые излучает поток. До первого события поставщик предоставляет своим зависимым лицам начальное значение (также типаT), который поставляется черезinitialDataпараметр конструктора. Как только поток выпустил хотя бы одно событие, провайдер предоставляет своим иждивенцам самое последнее отправленное событие. УвидетьStreamProvider APIдля вариантов, управляющих потоками.

Вот пример StreamProvider, который эмулирует загрузку данных:

StreamProvider<int>(
initialData: 0,
builder: (context) {
// Pretend this is loading data and reporting percent loaded.
return Stream<int>
.periodic(Duration(milliseconds: 100), (count) => count + 1)
.take(100);
},
child: ...
}

И вот пример зависимого, который использует этот StreamProvider:

Consumer<int>(
builder: (context, percentDone, child) {
if (percentDone < 100) {
return Text("Loading... ($percentDone% done)");
}
return Text("Done loading!");
},
),

Вы найдете полный источник для этого примера приложения StreamВот,

Чтобы установить StreamProvider из StreamController, используйтеStreamProvider<T>.controllerконструктор вместо. Этот последний конструктор необходимо использовать, если вы хотите, чтобы провайдер закрыл поток при его удалении;StreamProvider<T>никогда не закрывает поток

FutureProvider

FutureProviderполучает значениебудущееи предоставляет это значение своим зависимым виджетам. Используйте провайдера типаFutureProvider<T>чтобы получить значениеFuture<T>, Это значение имеет типTи представляет государство.

Говорят, что FutureProvider «подписывается» на будущее, чтобы получить значение будущего при завершении. До завершения провайдер предоставляет своим иждивенцам начальное значение (также типаT), поставляемый черезinitialDataпараметр конструктора. После завершения провайдер предоставляет своим иждивенцам значение завершенного будущего. Таким образом, для иждивенцев доступны только два значения - начальное значение и значение при завершении - и, следовательно, иждивенцы перестраиваются не более одного раза.

Вот пример FutureProvider, который эмулирует сохранение данных:

FutureProvider<bool>(
initialData: true,
builder: (context) {
// Pretend we're saving data and it takes 4 seconds.
return Future.delayed(Duration(seconds: 4), () => false);
},
child: ...
),

А вот пример зависимого, который использует этот FutureProvider:

Consumer<bool>(
builder: (context, saving, child) {
return Text(saving ? "Saving..." : "Saved!");
},
),

Вы найдете полный источник для этого примера приложения FutureВот,

ListenableProvider и ChangeNotifierProvider

ListenableProviderи его подклассChangeNotifierProviderотличаются от провайдеров, о которых говорилось ранее, тем, что они предоставляют источник состояния в качестве значения. Государственный источникListenableтакие какChangeNotifier, Поставщик подписывается на Listenable для получения уведомлений об изменениях состояния. Когда Listenable уведомляет провайдера об изменении состояния, провайдер предоставляет своим иждивенцам само Listenable в качестве значения. Зависимые лица рассматривают Listenable как модель, получая доступ к своим членам, чтобы получить состояние, в котором они нуждаются.

Следующая диаграмма иллюстрирует процесс восстановления для изменения состояния при использовании ListenableProvider или ChangeNotifierProvider:

Процесс восстановления иждивенцев выглядит следующим образом:

  1. Что-то вызывает изменение состояния в Слушаемом. Диаграмма изображает один из двух зависимых виджетов, вызывающих это изменение. Например, зависимый виджет может быть кнопкой, которая изменяет состояние при нажатии. Виджет кнопки должен иметь доступ к Listenable, чтобы изменить его состояние. Он получает Слушаемый либо по телефонуProvider.of<T>()или получив его в качестве параметраbuilderфункция вConsumer<T>,
  2. При изменении состояния прослушиваемого прослушиваемый уведомляет провайдера об изменении состояния. Поставщик через свой внутренний InheritedWidget помечает зависимые от прослушивания виджеты для построения.
  3. Платформа Flutter перестраивает зависимые объекты, помеченные для построения, получая предоставленное значение в процессе, как объяснялось ранее. Однако в этом случае значение Listenable является предоставленным значением - одно и то же Listenable передается зависимым при каждой перестройке. Зависимые лица получают доступ к Listenable для того состояния, которое им необходимо для построения.

Подклассы источника состояния (или микшируются в) Listenable или ChangeNotifier. использованиеListenableProvider<T>дляTкоторый наследует от Listenable, и использоватьChangeNotifierProvider<T>дляTэто наследуется от ChangeNotifier. Технически, вы можете использовать ChangeNotifier сListenableProvider<T>, ноChangeNotifierProvider<T>обеспечивает дополнительное преимущество удаления ChangeNotifier, когда сделано с помощью ChangeNotifier'sdispose()метод.

Вот пример ChangeNotifier, который реализует счетчик:

class Counter with ChangeNotifier {
int count = 0;void increment() {
++count;
notifyListeners();
}
}

Вы можете сделать этот источник состояния доступным для зависимых лиц следующим образом:

ChangeNotifierProvider<Counter>(
builder: (context) => Counter(),
child: ...
),

Вот зависимый виджет, который перестраивается при каждом изменении счетчика:

Consumer<Counter>(
builder: (context, counter, child) => Text(
'${counter.count}',
style: Theme.of(context).textTheme.display1,
),
),

А вот зависимый виджет, который создается только один раз, потому что ему нужна ссылка на источник состояния, но он не меняется при изменении состояния:

Builder(builder: (context) {
final counter = Provider.of<Counter>(context, listen: false);
return RaisedButton(
onPressed: () => counter.increment(),
child: Text("Increment"),
);
}),

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

Вы найдете полный источник для этого примера приложения ChangeNotifierВот,

ValueListenableProvider

Несмотря на название,ValueListenableProviderэто не вид ListenableProvider. Он работает больше как StreamProvider или FutureProvider, хотя его источник состояния,ValueListenableэто своего родаListenable, ValueListenable - это интерфейс, для которого Flutter предлагает две реализации:Анимацияа такжеValueNotifier,

ValueListenableProvider подписывается на ValueListenable для получения уведомлений об изменении значения. Получив уведомление об изменении, он получает значение из ValueListenable и предоставляет это значение своим зависимым элементам в качестве состояния. использованиеValueListenableProvider<T>получить значения типаTизValueListenable<T>,

Поскольку этот поставщик получает значение из ValueListenable, он может получить начальное значение, чтобы предоставить иждивенцев до получения первого уведомления об изменении, поэтому нетinitialDataпараметр необходим.

Вот пример ValueListenable, который реализует обратный отсчет:

class CountDown extends ValueNotifier<int> {
CountDown(int downFrom) : super(downFrom) {
scheduleDecrement();
}void scheduleDecrement() {
Future.delayed(Duration(seconds: 1), () {
if (--value > 0) scheduleDecrement();
});
}
}

Вы можете сделать этот источник состояния доступным для зависимых лиц следующим образом:

ValueListenableProvider<int>(
builder: (context) => CountDown(10),
child: ...
),

Зависимый слушает значение следующим образом:

Consumer<int>(
builder: (context, count, child) {
if (count > 0) {
return Text("T minus $count seconds");
}
return Text("Blast off!");
},
),

В этой реализации ValueListenable асинхронно предоставляет значения. Это связано с тем, что ValueListenableProvider не предоставляет зависимым элементам ссылку на ValueListenable, как это делает ListenableProvider - пользовательский интерфейс не может напрямую изменить значение. (Эта демонстрация обратного отсчета была бы лучше реализована в виде потока с StreamProvider.¹)

Вы найдете полный источник для этого примера приложения ValueNotifierВот,

Обратите внимание, что при использовании конструктораValueListenableProvider<T>, государственный источникдолженбытьValueNotifierи не простоValueListenable Это потому, что эта версия провайдера вызываетdispose()метод доступен наValueNotifierкогда провайдер уничтожен. Государственный источник может быть любымValueListenableпри использованииValueListenableProvider<T>.valueконструктор. Мы посмотрим на.valueпровайдеры в ближайшее время.

Простой поставщик ванили

поставщикКласс реализует самый основной вид провайдера. Мы могли бы назвать «простой ванильный провайдер». Этот провайдер просто делает значение доступным для дочерних виджетов, не подписывая провайдера на это значение. Нет никаких ограничений по виду стоимости. Однако, когда значение является источником состояния, механизмы за пределами поставщика отвечают за обработку изменения состояния.

провайдер README включает в себя примердемонстрация использования простого ванильного поставщика как со значением состояния, так и с источником состояния. StatefulWidget использует состояние, которое содержит_countпеременная. Мы дублируем код штата здесь:

class ExampleState extends State<Example> {
int _count; void increment() {
setState(() {
_count++;
});
} @override
Widget build(BuildContext context) {
return Provider.value(
value: _count,
child: Provider.value(
value: this,
child: widget.child,
),
);
}
}

Обратите внимание, чтоbuild()Метод возвращает провайдера, который содержит вложенный провайдер. Внешний поставщик предоставляет значение типа integer зависимым виджетам. Вложенный поставщик предоставляет сам объект State зависимым виджетам. (На данный момент, игнорируйте тот факт, что он использует.valueконструкторы - мы рассмотрим их в следующем разделе.)

В этом примере объект State служит источником состояния для целочисленного значения состояния. Имеетincrement()метод для изменения состояния. Изменение состояния приводит к восстановлению обоих провайдеров. Тем не менее, потому что внутреннийchildссылается на уже существующий виджет, внутреннийchildне перестраивать автоматически; иждивенцы восстанавливаются только при изменении их зависимого состояния.

Зависимые виджеты получают значение состояния, вызываяProvider.of<int>()и они получают источник состояния, вызываяProvider.of<ExampleState>(), Когда зависимый звонитincrement()в ExampleState значение состояния изменяется, и все зависимые элементы прослушивают значения типаintперестраивать. Однако, поскольку значение типа ExampleState никогда не изменяется (остается тем же экземпляром), ни один из зависимых от ExampleState не перестраивается, независимо от того, прослушивают ли они изменения, используяlisten: true,

Поставщики .value и Уничтожающие Поставщики

Существует как минимум две версии каждого типа провайдера. Одна версия отвечает за создание и размещение государственного источника. Эта версия «владеет» государственным источником и управляет его временем жизни. Это версия, которую мы представили до сих пор. Давайте назовем их «избавляющимися провайдерами». Другая версия ссылается только на источник состояния и не управляет его временем жизни. Эта версия провайдера имеет конструктор, заканчивающийся на.value, Мы их называем.valueпровайдеры».

Предположим, что мы хотим использовать ChangeNotifierProvider с классом Counter, который реализует ChangeNotifier. Чтобы провайдер управлял временем жизни счетчика, мы должны создать провайдера утилизации следующим образом:

ChangeNotifierProvider<Counter>(
builder: (context) => Counter(),
child: ...
),

Это откладывает создание источника источника для поставщика. Это «ленивая» конструкция в том смысле, что провайдер не создает источник состояния, пока Flutter не приступит к его построению. После создания провайдер использует этот экземпляр источника состояния до тех пор, пока провайдер не будет уничтожен. На этом этапе, чтобы высвободить ресурсы источника состояния, провайдер вызываетdispose()илиclose()метод на государственном источнике, по мере необходимости.

Сравните это с.valueпровайдеры, которые не управляют временем жизни источника. В нашем примере Counter, который реализует ChangeNotifier, предположим, что мы создаем экземпляр Counter вне поставщика и хотим использовать этот экземпляр в поставщике. Мы бы использовали.valueконструктор:

ChangeNotifierProvider<Counter>.value(
value: counter,
child: ...
),

В распоряжении поставщиков,builderПараметр предоставляет функцию для создания источника состояния. В.valueпровайдеры, есть вместоvalueпараметр, который принимает ссылку на источник состояния. Будьте осторожны, чтобы не перепутатьbuilderпараметр провайдера сbuilderпараметрстроительВиджет: первый создает источник состояния, второй создает виджет.

Утилизирующая версия простого провайдера ванили позволяет вам передать конструкторуdisposeфункция утилизации государственного источника. Поставщик вызывает эту функцию, когда она сама удаляется.

Обычно рекомендуется избавляться от поставщиков, чтобы вам не пришлось беспокоиться о хранении и утилизации источника состояния. Тем не мение,.valueпровайдеры полезны как минимум в трех ситуациях:

  1. У тебя естьзначение верхнего уровнячто вы хотите сделать доступными дочерние виджеты, которые не имеют (или не должны) иметь доступ к значению верхнего уровня.
  2. У вас есть переменная состояния в состоянии StatefulWidget, которую вы хотите сделать доступной для потомков виджетов.
  3. У вас есть зависимый виджет, который получил значение объекта от поставщика-предка, и вы хотите сделать одно из свойств этого объекта доступным для потомков виджетов через тип свойства. Например, у вас может быть зависимость, которая получила состояние типа Counter, и вы хотите сделатьcounter.countдоступны потомкам, которые запрашивают состояние типа integer, ничего не зная о Counter

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

Архитектура для Государственного источника

Теперь мы рассмотрели последнюю часть схемы архитектуры. Все, что осталось, - это средства, с помощью которых провайдеры приобретают государство из государственных источников. Давайте рассмотрим этот процесс, выделенный здесь на диаграмме UML:

Как мы видели у простого провайдера, у провайдера не должно быть источника состояния. Это может просто выставить неизменные ценности. Диаграмма изображает это, указывая, что источник состояния является необязательным.

Когда есть источник состояния, поставщик является либо поставщиком, который владеет им, либо.valueпоставщик, который ссылается на это.

Поставщик подписывается на источник состояния, чтобы получать уведомления об изменении состояния. Некоторые государственные источники предоставляют новое значение состояния вместе с уведомлением. Фьючерсы и потоки являются примерами таких государственных источников. Другие источники состояния, такие как ValueListenable (включая ValueNotifier), предоставляют только уведомление. В этом последнем случае поставщик извлекает значение состояния из источника состояния.

При использовании ChangeNotifier или при использовании Listenable с ListenableProvider сам источник состояния является значением, предоставляемым зависимым. В этом случае иждивенцы сами читают состояние напрямую из источника состояния или напрямую обращаются к источнику состояния, чтобы изменить его состояние.

Теперь мы объяснили всю схему архитектуры. вследующая и последняя статьяиз этой серии мы собрали все вместе, перечислим некоторые дополнительные функции пакета провайдера и объясним, почему можно использовать пакет провайдера вместо простого использованияInheritedWidget,


Поздравляем!Вы прошли через часть 2 из Понимание провайдера в диаграммах. Это была самая жесткая из трех частей. Как только вы восстановитесь, пожалуйста, перейдите наЧасть 3: Архитектурагде мы в основном все обобщаем.

Not Мне не ясно, когда кто-либо выберет использование ValueListenableProvider вместо StreamProvider, если только ValueListenable не являетсяАнимация, Возможно, главное преимущество состоит в том, что ValueListenable может обеспечить начальное значение, лучше отделяя бизнес-логику от пользовательского интерфейса.

https://www.twitter.com/FlutterCom

Оригинальная статья

Footer decor

© machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map