ark_di_flutter 0.1.0-dev.1
ark_di_flutter: ^0.1.0-dev.1 copied to clipboard
Flutter scopes and BuildContext access for Ark DI dependency containers.
Ark DI Flutter #
Flutter scope and BuildContext integration for
Ark DI.
Ark DI Flutter connects an existing DiContainer hierarchy to the widget
tree. It owns no global container, performs no reflection, and does not turn
dependency injection into state management. Application objects continue to
receive dependencies through constructors; widgets use the container at
explicit composition boundaries.
0.1.0-dev.1is a prerelease. The lifecycle model is implemented and tested, but public API details may change before the first stable version.
Installation #
dependencies:
ark_di: ^0.1.0-dev.1
ark_di_flutter: ^0.1.0-dev.1
import 'package:ark_di/ark_di.dart';
import 'package:ark_di_flutter/ark_di_flutter.dart';
Root scope #
Build the application container at the Composition Root and expose it above the application:
final DiContainer application = DiContainer.build((binder) {
binder.bindLazySingleton<ApiClient>(
(resolver) => ApiClient(),
dispose: (client) => client.close(),
);
});
runApp(
DiRootScope(
container: application,
child: const Application(),
),
);
DiRootScope owns its container by default and starts close() when the
widget stops exposing it. Use DiScopeOwnership.external when another object
controls the root lifecycle.
Because Flutter disposal is synchronous while DiContainer.close() is
asynchronous, closing continues without blocking the widget tree. Supply
onCloseError to receive teardown failures. Without a handler, failures are
reported through the Zone active when closing starts.
Child scope #
DiScope creates and owns a real child container. Missing dependencies fall
back through the Ark DI parent hierarchy:
DiScope(
configure: (binder) {
binder.bindInstance<FeatureId>(featureId);
binder.bindLazySingleton<FeaturePresenter>(
(resolver) => FeaturePresenter(
repository: resolver.get<UserRepository>(),
featureId: resolver.get<FeatureId>(),
),
dispose: (presenter) => presenter.close(),
);
},
child: const FeatureScreen(),
)
The configuration callback is required and runs once for each parent-container
identity. Ark DI registrations are immutable after creation. Give DiScope a
new Key when changed configuration must create a fresh scope.
BuildContext access #
final UserRepository repository = context.readDi.get<UserRepository>();
final Session session = await context.readDi.getAsync<Session>();
The extension exposes four accessors:
| Accessor | Subscribes to scope replacement | Missing scope |
|---|---|---|
context.di |
Yes | Throws DiScopeNotFoundException |
context.maybeDi |
Yes | Returns null |
context.readDi |
No | Throws DiScopeNotFoundException |
context.maybeReadDi |
No | Returns null |
Use di from build or didChangeDependencies when the widget must follow a
replacement scope. Use readDi for one-off event-handler access. Do not cache
a container retrieved from BuildContext for later lifecycle callbacks.
Opt-in Service Locator #
The main library contains no Service Locator. Compatibility for applications that explicitly require one is isolated behind another import:
import 'package:ark_di_flutter/service_locator.dart';
abstract final class ApplicationDependencies {
static final DiServiceLocator locator = DiServiceLocator();
}
DiServiceLocator is an ordinary object. The package creates no global or
static instance. attach and detach are explicit, and the locator never owns
or closes the attached container.
Scope boundaries #
Ark DI Flutter handles widget-tree placement, child-scope lifetime, context
lookup, and close-error delivery. It does not manage UI state, rebuild widgets
when dependency data changes, create Presenters automatically, or discover
dispose() methods by convention.
See the runnable example and the Ark DI architecture guide.