depend 5.1.0
depend: ^5.1.0 copied to clipboard
depend simplifies dependency management in Flutter apps, providing easy initialization and access to services across the widget tree.

depend is a library for dependency management in Flutter applications. It provides a convenient way to initialize and access services and repositories via InheritedWidget.
Features 🚀 #
- Dependency Initialization: Prepare all dependencies before the app launches.
- Global Access: Access dependencies from anywhere in the widget tree.
- Parent Dependencies Support: Easily create nested or connected dependencies.
- Ease of Use: Integrate the library into existing code with minimal changes.
Table of Contents #
- Features 🚀
- Table of Contents
- Installation
- Usage Examples
- Migration Guide
- Code Coverage
Installation #
Add the library to the pubspec.yaml of your project:
dependencies:
depend: ^latest_version
Install the dependencies:
flutter pub get
Usage Examples #
Example 1: Simple Initialization #
Step 1: Define the Dependency
Create a class that extends DependencyContainer and initialize your dependencies:
class RootContainer extends DependencyContainer {
final ApiService apiService;
RootContainer({required this.apiService});
void dispose() {
apiService.dispose();
}
}
Step 2: Define the DependencyFactory
Create a class that extends DependencyContainer and initialize your dependencies:
class RootDependencyFactory extends DependencyFactory<RootContainer> {
Future<RootContainer> create() async {
return RootContainer(
apiService: await ApiService.initialize(),
);
}
// or
RootContainer create() {
return RootContainer(
apiService: ApiService.initialize(),
);
}
}
Step 3: Use DependencyScope
Wrap your app in a DependencyScope to provide dependencies:
void main() {
runApp(
DependencyScope<RootContainer, RootFactory>(
factory: RootFactory(),
placeholder: const Center(child: CircularProgressIndicator()),
builder: (BuildContext context) => const MyApp(),
),
);
}
Step 4: Access the Dependency in a Widget
You can now access the dependency using DependencyProvider anywhere in the widget tree:
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final apiService = DependencyProvider.of<RootContainer>(context).apiService;
return FutureBuilder(
future: apiService.getData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return Text('Data: ${snapshot.data}');
},
);
}
}
Example 2: DependencyProvider #
final RootContainer dep = await RootFactory().create();
DependencyProvider<RootContainer>(
dependency: dep,
builder: () => YourWidget();
// or
child: YourWidget()
)
class YourWidget extends StatelessWidget {
@override
Widget build(BuildContext) {
root = DependencyProvider.of<RootContainer>(context);
...
}
}
Example 3: DependencyScope #
DependencyScope<RootContainer, RootFactory>(
factory: RootFactory(),
builder: (BuildContext context) => Text('Inject'),
placeholder: Text('Placeholder'),
errorBuilder: (Object? error) => Text('Error'),
),
Example 4: Lazy Initialization #
The library provides LazyGet and LazyFutureGet classes for lazy initialization of services. Dependencies are created only when they are first accessed, which improves application startup time.
Using LazyGet for Synchronous Dependencies
class RootContainer extends DependencyContainer {
// Service will be created only when accessed for the first time
final LazyGet<ApiService> apiService = LazyGet(() => ApiService());
final LazyGet<DatabaseService> database = LazyGet(() => DatabaseService());
void dispose() {
// Check if the service was initialized before disposing
if (apiService._instance != null) {
apiService.instance.dispose();
}
}
}
// Usage in widgets
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final container = DependencyProvider.of<RootContainer>(context);
// ApiService is created only at this moment
final api = container.apiService.instance;
return Text('Service initialized: ${api.isReady}');
}
}
Using LazyFutureGet for Asynchronous Dependencies
class RootContainer extends DependencyContainer {
// Service with async initialization
final LazyFutureGet<DatabaseService> database =
LazyFutureGet(() async {
final db = DatabaseService();
await db.initialize();
return db;
});
final LazyFutureGet<AuthService> authService =
LazyFutureGet(() async => await AuthService.create());
}
// Usage in widgets
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final container = DependencyProvider.of<RootContainer>(context);
return FutureBuilder<DatabaseService>(
// Database is initialized only when this widget is built
future: container.database.instance,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
return Text('Database ready: ${snapshot.data?.isConnected}');
},
);
}
}
Benefits of Lazy Initialization:
- Faster App Startup: Dependencies are created only when needed
- Memory Optimization: Unused services don't consume memory
- Flexible Initialization: You can control when heavy operations are performed
- Simple API: Easy to use with both sync and async dependencies
