InjectX
A lightweight, easy-to-use service locator implementation for Dart applications. This package provides a simple dependency injection container that helps manage application dependencies with minimal setup.
Features
- Simple registration and retrieval of dependencies
- Singleton instance management
- Automatic disposal of services
- Type-safe dependency injection
- Angular-style
inject
function - Zero external dependencies
Installation
Add this to your package's pubspec.yaml
file:
dependencies:
inject_x: ^0.0.5
Usage
Basic Usage
// Register your dependencies
InjectX.add<UserService>(UserService());
InjectX.add<AuthService>(AuthService());
// Retrieve instances
final userService = InjectX.get<UserService>();
final authService = InjectX.get<AuthService>();
// Alternatively, use Angular-style injection
final userService = inject<UserService>();
Init Method
If your class defines an init()
method, it will be called automatically before the first injection. This is useful when your service depends on other services that need to be resolved after construction — particularly in cases of circular dependencies.
class UserService {
late AuthService authService;
void init() {
authService = inject<AuthService>();
}
}
The init()
method is called only once, just before the first access via get()
or inject()
.
Async Init Method
If your class has an async
init()
method (returning a Future
), you can use injectAsync<T>()
or InjectX.getAsync<T>()
to ensure initialization is awaited before use.
class ConfigService {
String? config;
Future<void> init() async {
await Future.delayed(Duration(milliseconds: 100));
config = 'loaded';
}
}
void main() async {
InjectX.add(ConfigService());
final config = await injectAsync<ConfigService>();
}
Automatic Disposal
InjectX automatically calls a service’s dispose()
method if it exists when the service is removed:
class DatabaseService {
void dispose() {
// Cleanup resources
}
}
// Register the service
InjectX.add<DatabaseService>(DatabaseService());
// Later, remove it
InjectX.remove<DatabaseService>(); // dispose() will be called automatically
API Reference
Methods
add<T>(T instance)
: Register a new dependencyget<T>()
: Retrieve a registered dependency, callinginit()
if definedgetAsync<T>()
: Retrieve a registered dependency, awaitinginit()
if it's asyncremove<T>()
: Remove a registered dependency and calldispose()
if definedlength
: The number of registered dependenciesclear()
: Remove all dependencies and dispose each (if supported)
Helper Functions
inject<T>()
: Angular-style helper to callInjectX.get<T>()
injectAsync<T>()
: Angular-style helper for services with asyncinit()
Error Handling
The package includes error handling for common scenarios:
// Attempting to retrieve a non-existent dependency
try {
final service = InjectX.get<UnregisteredService>();
} catch (e) {
// Throws StateError: No instance registered for type UnregisteredService
}
Best Practices
- Register all dependencies early in your app lifecycle
- Use meaningful type parameters for clarity
- Implement
dispose()
for services that require cleanup - Remove services when no longer needed (e.g., on module unload)
Example
class UserService {
void dispose() {
// Cleanup
}
}
class AuthService {
final UserService userService;
AuthService(this.userService);
}
void main() {
// Register services
InjectX.add<UserService>(UserService());
// Register a dependent service
InjectX.add<AuthService>(AuthService(inject<UserService>()));
// Use services
final userService = inject<UserService>();
final authService = inject<AuthService>();
// Cleanup
InjectX.remove<AuthService>();
InjectX.remove<UserService>();
}
Contributing
Contributions are welcome! Please feel free to submit a pull request.
For major changes, open an issue first to discuss what you'd like to propose.
License
This project is licensed under the MIT License — see the LICENSE file for details.