Руководства

Scope Flutter-приложения

Контейнер приложения, feature Scope и разрешение зависимостей через BuildContext.

v1.1.0Средний уровеньark_di_flutter

Scope Flutter-приложения

В этом руководстве контейнер приложения размещается в дереве Widget, а под ним создаётся контейнер функции с более коротким жизненным циклом. Приложение владеет общей инфраструктурой; Scope функции — только локальными объектами.

1. Установите оба пакета

shell
flutter pub add ark_di:^1.1.0 ark_di_flutter:^1.1.0

Добавьте ark_di как прямую зависимость, если код приложения импортирует DiContainer, DiBinder или другой тип core.

2. Создайте граф приложения до runApp

dart
void main() {
  final application = DiContainer.build((binder) {
    binder.bindInstance<GreetingRepository>(
      const GreetingRepository(),
    );
  });

  runApp(
    DiRootScope(
      container: application,
      child: const Application(),
    ),
  );
}

DiRootScope предоставляет существующий контейнер, но не создаёт регистрации во время build. Через DiScopeOwnership явно выберите, кто закрывает контейнер: Scope или Bootstrap.

3. Создайте Scope функции

Функция добавляет одно локальное значение и наследует Repository из родителя:

dart
final class GreetingFeature extends StatelessWidget {
  const GreetingFeature({super.key});

  @override
  Widget build(BuildContext context) => DiScope(
    configure: (binder) {
      binder.bindInstance<FeatureName>(
        const FeatureName('Ark DI Flutter'),
      );
    },
    child: const GreetingView(),
  );
}

configure выполняется один раз при создании контейнера. Если функция владеет Presenter, Controller или локальным сервисом с ресурсами, зарегистрируйте его с Disposer в этом дочернем Scope.

4. Разрешите зависимости через актуальный BuildContext

dart
final class GreetingView extends StatelessWidget {
  const GreetingView({super.key});

  @override
  Widget build(BuildContext context) {
    final repository = context.di.get<GreetingRepository>();
    final feature = context.di.get<FeatureName>();
    return Text(repository.greetingFor(feature.value));
  }
}

context.di подписывается на идентичность Scope и предназначен для build или didChangeDependencies. При замене контейнера предка виджет перестраивается с новым Scope. context.readDi выполняет разовое чтение в обратном вызове и не создаёт такую зависимость.

5. Учтите замену и завершение

При удалении DiScope закрывает дочерний контейнер и принадлежащие ему зависимости. Родитель остаётся открытым. Если меняется ближайший родительский контейнер, DiScope создаёт новый дочерний граф и закрывает предыдущий.

Не сохраняйте context.di или полученный объект функции в глобальной переменной с более долгим временем жизни. Объект ограничен Scope, который его предоставил.

Распределение объектов

Scope приложенияScope функцииState Widget
API-клиенты, общие Repository, прикладные сервисыPresenter, Coordinator, локальный сервис функцииAnimationController, TextEditingController, FocusNode и состояние отрисовки

Такое распределение — архитектурный выбор, а не ограничение пакета. Основное правило: объект с коротким жизненным циклом не покидает своего Scope и не попадает к более долгоживущему владельцу.