Гаджет конструктор | Funny Gifts

Гаджет конструктор | Funny Gifts Гаджет

Почему так происходит

Если в двух словах. то виджеты и их контроллеры, участвующие в GetPageRoute, синхронизируют свои жизненные циклы, и все работает из коробки — при смене роута в навигаторе нужные контроллеры заново инициализируются, ненужные удаляются. Для операций вне роутинга это не предусмотрено. А наши кейсы — как раз вне роутинга.

Statex* — автоинжектирование без ограничений

На стороне виджетов введены 2 класса:

1. StatexWidget — базовый абстрактный класс

Его задача в том, чтобы позади основного дерева виджетов внедрить служебный микровиджет _StatexWidgetInjector (по сути, пустой контейнер). Вся работа производится в этом виджете.

abstract class StatexWidget<T extends StatexController>
    extends StatelessWidget {
  /// Базовый конструктор для передачи билдера и свойств.
  /// Под капотом вызывает Get.put(...), передавая туда билдер, тег
  /// и флаг permanent.
  /// Удобен для передачи параметров прямо по месту вызова, но не поддерживает
  /// принцип Dependency Inversion, так как точный тип контроллера нужно знать
  /// в точке вызова.
  /// Если требуется что-то типа Get.lazyPut<Base>(()=>Inherited()),
  /// то следует воспользоваться конструктором [StatexWidget.find]
  ///
  /// ```
  /// class BusinessPage extends StatexWidget<_BusinessPageControllerImpl> {
  ///   BusinessPage() : super(() => _BusinessPageControllerImpl(),
  ///     tag: 'TAG', permanent: true, args: {'key': value} );
  ///
  /// ```
  const StatexWidget(
    this.builder, {
    this.tag,
    this.permanent = false,
    this.args = const <String, dynamic>{},
    Key? key,
  }) : super(key: key);

  /// Конструктор для работы в паре с [Get.lazyPut<Some>(()=>SomeImpl())].
  /// Другими словами, для поддержания концепции Dependency Inversion.
  ///
  /// [markAsPermanent] используется в случаях, 
  ////  когда конструктор `StatexWidget.find` будет вызываться
  ///   в паре с ранее зарегистрированной ленивой фабрикой Get.lazyPut.
  ///   Для  Get.lazyPut нельзя сделать контроллер перманентным, 
  ///   только возобновляемым при помощи свойства `fenix`.
  ///   Но fenix заново создает контроллер, убивая его состояние. 
  ///   В случае создания контроллера [markAsPermanent] передаст 
  ///   свое значение в инжектор Get.put(..., permanent = markAsPermanent), 
  ///   тем самым создав перманентный контроллер.
  ///   И соответственно, при [dispose] не будет удаления Get.delete<T>
  ///   для этого типа.
  ///
  /// ```
  ///   // Где-то в инжекторе определяем фабрику и параметры,
  ///   // подставляя имплементацию
  ///   Get.lazyPut<HomePageController>(
  ///     () => HomePageControllerImpl(),
  ///     fenix: true,
  ///   );
  ///
  ///   // Используем  [StatexWidget.find], передавая дополнительные параметры.
  ///   // Если инстанс не существует, он будет создан с нужными параметрами.
  ///   // Иначе будет найден и выдан текущий инстанс.
  ///   class HomePage extends StatexWidget<HomePageController> {
  ///     HomePage({Key? key}) : super.find(
  ///           markAsPermanent: true,
  ///           key: key,
  ///   );
  ///
  /// ```
  const StatexWidget.find({
    String? tag,
    bool markAsPermanent = false,
    Map<String, dynamic> args = const <String, dynamic>{},
    Key? key,
  }) : this(null, tag: tag, permanent: markAsPermanent, args: args, key: key);

  /// [builder] обязателен для базового конструктора, но не используется
  /// для [StatexWidget.find]
  final InstanceBuilderCallback<T>? builder;

  ///
  final String? tag;
  final bool permanent;
  final Map<String, dynamic> args;

  T get controller => GetInstance().find<T>(tag: tag);

  Widget buildWidget(BuildContext context);

  /// Идея в том, чтобы внедрить виджет-менеджер времени 
  /// жизни контроллера в стек позади основного дерева клиента.
  @override
  Widget build(BuildContext context) {
    // Необходимый стек для внедрения [_StatexWidget]
    return Stack(
      fit: StackFit.passthrough,
      children: [
        // Wrapping уменьшает геометрию виджета до минимально возможной
        Wrap(
          children: [
            _StatexWidgetInjector<T>(
              builder,
              tag: tag,
              permanent: permanent,
              args: args,
            ),
          ],
        ),
        buildWidget(context),
      ],
    );
  }
}

2. _StatexWidget State: Виджет управления состояниями контроллера.

/// Контрольный [StatefulWidget]
class _StatexWidgetInjector<T extends StatexController> extends StatefulWidget {
  _StatexWidgetInjector(
    InstanceBuilderCallback<T>? builder, {
    this.tag,
    this.permanent = false,
    Map<String, dynamic> args = const <String, dynamic>{},
    Key? key,
  }) : super(key: key) {
    // Инжектирование контроллера прямо в конструкторе виджета.
    final inst = GetInstance();
    if (builder != null && !inst.isRegistered<T>(tag: tag)) {
      inst.put(builder(), tag: tag, permanent: permanent);
    }
    final c = inst.find<T>(tag: tag);
    c.args = args;
  }

  final String? tag;
  final bool permanent;

  @override
  _StatexWidgetInjectorState<T> createState() =>
      _StatexWidgetInjectorState<T>();
}

/// Состояние для [_StatexWidgetInjector]
/// Управляет вызовами [onWidgetInitState], [onWidgetDisposed]
/// и в случае необходимости, удаляет инстанс контроллера
/// из памяти
class _StatexWidgetInjectorState<T extends StatexController>
    extends State<_StatexWidgetInjector<T>> {
  @override
  initState() {
    super.initState();
    final wc = GetInstance().find<T>(tag: widget.tag);
    wc.onWidgetInitState();
  }

  @override
  void dispose() {
    final inst = GetInstance();
    if (inst.isRegistered<T>(tag: widget.tag)) {
      final wc = inst.find<T>(tag: widget.tag);
      wc.onWidgetDisposed();
      if (!widget.permanent) {
        Get.delete<T>(tag: widget.tag);
      }
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => Container();
}

Это StatefulWidget и поэтому он поддерживает полный жизненный цикл при перестройке дерева, в котором находится, включая initState и dispose. Этим и воспользуемся.

Гаджет:  Global chip shortage could affect gadget prices in 2022; impact on Samsung folding phones unclear, Tech News News & Top Stories - The Straits Times

Вот как это работает:

  1. Переданный в конструкторе билдер (если есть), создаст нам инстанс контроллера с требуемыми параметрами, или вернет существующий

  2. В ином случае мы попытаемся найти инстанс через GetInstance.find

  3. Напоследок передадим в инстанс аргументы

  4. Далее, в _StatexWidgetState.initState, вызывается onInitWidgetState давая возможность произвести нужные действия в момент инициализации дерева

  5. А в _StatexWidgetState.dispose мы производим вызов onWidgetDisposed, и при необходимости удаляем контроллер

Statexview.find — теперь и с инверсией зависимостей

Отдельного разговора заслуживает именованный конструктор StatexView.find.

Передача билдера конкретного типа в конструктор не вписывается в Dependency Inversion. Если необходимо управлять имплементациями, подойдет связка Get.lazyPut<Some>(()=>SomeImpl) StatexView.find().

Это работает так

// [1.] 
// Где-то в инжекторе определяется имплементация интерфейса,
// например, вот так
  Get.lazyPut<HomePageController>(
    () => HomePageControllerImpl(),
    fenix: true, 
  );
// или так
  Get.lazyPut<HomeSubPageController>(
    () => HomeSubPageControllerImpl(),
    tag: HomeSubPageController.someTagForFindStrategy,
    fenix: true,
  );


// [2.]
// В конструкторе виджета идет обращение к StatexView.find
// вот так
  HomePage({Key? key})
      : super.find(
          markAsPermanent: true,
          key: key,
        );
// или так
  HomeSubPage({Key? key})
      : super.find(
          key: key,
          tag: HomeSubPageController.someTagForFindStrategy,
        );

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

Гаджет конструктор | funny gifts

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

gadzhet konstruktor

Гаджет конструктор

Где купить: magic-present.su

Цена: 390 рублей

Элементы:

– солнечная батарея;

– мини-электродвигатель;

Гаджет:  Смотреть онлайн взвешивание и битвы взглядов UFC Вегас 34: Каннонир vs. Гастеллум. Прямой эфир 20 августа 2021. Результаты. | Все о Боевых Искусствах и Спорте

– 22 пластиковые детали, не требующие склейки и делающие сборку и разборку конструктора совершенно не скучной.

Шесть фигур

Конструктор дает возможность любому попробовать свои силы в смекалке и в легкой конструкторской сноровке и собрать шесть моделей. Чуть-чуть усилий и на столе поочередно появляется мельница, робот, мини-вентилятор, самолет и даже вертолет. Но самое удивительное заключается в том, что благодаря солнечной батарее и мини-мотору, каждая из фигур закрутиться, поедет, задвигается. И все это от любого источника питания будь то солнце, или лампочка.

Игрушка дает возможность окунуться в мир фантазии не только ребенку, но и взрослому человеку, скоротать время на работе или попросту удивить друзей и знакомых. Будьте оригинальными при выборе подарка и ответная радостная реакция виновника торжеств, а  вернется сторицей. Ну а если вы вообще масштабно мыслите и уже увидели перспективу, то купить гаджет конструктор во множественном числе для большой компании и у вас появится шанс создать нечто большее, чем шесть фигур. Дерзайте и сотворите чудо!

Гаджет конструктор 6 1 — купите гаджет конструктор 6 1 с бесплатной доставкой на алиэкспресс version

Перед покупкой сравните цены на гаджет конструктор 6 1, прочитайте реальные отзывы покупателей, ознакомьтесь с техническими характеристиками.

Закажите гаджет конструктор 6 1 онлайн с доставкой по России: товары с пометкой Plus доступны с ускоренной доставкой и улучшенными условиями возврата.

На Алиэкспресс гаджет конструктор 6 1 всегда в наличии в большом ассортименте: на площадке представлены как надежные мировые бренды, так и перспективные молодые.

Как с этим бороться

Для решения этих задач я использую небольшую надстройку в виде двух классов на стороне виджета и одного на стороне контроллера.

Как собрать все это воедино

  1. Унаследовать контроллер от StatexController. Если есть необходимость, переопределить нужные методы

  2. Унаследовать Widget от StatexWidget

  3. В конструкторе вызвать конструктор суперкласса

    1. либо основной — для простого инжектирования

    2. либо super.find для связки с ленивой инициализацией. Имеет смысл только для инверсии зависимостей

  4. Вместо build реализовать buildWidget

  5. Профит

Гаджет:  Как поменять иконку приложения на Android: Samsung, Xiaomi, Honor

Подготовка контроллера

Чтобы все окончательно заработало, на стороне контролллера введен тип StatexController

abstract class StatexController extends GetxController {

  final _args = <String, dynamic>{};

  Map<String, dynamic> get args => _args;

  set args(Map<String, dynamic> value) => _args.assignAll(value);

  /// Вызывается в момент [_StatexWidgetState.initState].
  /// Таким образом можно отлавливать момент перехода на страницы
  /// в [PageView], например
  void onWidgetInitState() {}

  /// Вызывается в момент [_StatexWidgetState.dispose].
  void onWidgetDisposed() {}
}

Конкретно инжектирования там касается только два метода-события, которые вызываются из StatexWidget в нужное время.

Пример 1. управлять контроллерами в страницах pageview

Архитектура PageView такова, что субстраницы строятся одномоментно в процессе build и при переходах не пересоздаются. Но предположим, что по бизнес-логике необходимо рассматривать эти субстраницы, как отдельные элементы, например инициализировать и отключать таймеры, обновлять поля, открывать и закрывать какие-то ресурсы при переходе между ними. Явно просится прикрутить по контроллеру к каждой из них.

      body: PageView(
        controller: controller.pageController,
        children: [
          HomePage(), //   HomePageController
          BusinessPage(), //   BusinessPageController
        ],
      ),

Вообще, следует начать с того, что непонятно, куда прикручивать инжектирование. Биндить к странице-владельцу PageView? Но теряется контекстность применения, ведь контроллеры управляют данными конкретных субстраниц, а onInit/onReady/onClose контроллеров никак не будут соответствовать моментам переходов.

Из лога видно, что никакой привязки контроллеров не получается.

А вот как это должно быть:

Очевидно, что теперь жизненные циклы контроллеров страниц отслеживаются. Это позволяет управлять ресурсами в контексте бизнес-логики.

Оцените статью
GadgetManiac
Добавить комментарий