Руководства
Scope Flutter-приложения
Контейнер приложения, feature Scope и разрешение зависимостей через BuildContext.
Scope Flutter-приложения
В этом руководстве контейнер приложения размещается в дереве Widget, а под ним создаётся контейнер функции с более коротким жизненным циклом. Приложение владеет общей инфраструктурой; Scope функции — только локальными объектами.
1. Установите оба пакета
flutter pub add ark_di:^1.1.0 ark_di_flutter:^1.1.0
Добавьте ark_di как прямую зависимость, если код приложения импортирует DiContainer, DiBinder или другой тип core.
2. Создайте граф приложения до runApp
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 из родителя:
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
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 и не попадает к более долгоживущему владельцу.