get_it_lazyload
A Flutter package providing optimized lazy loading extensions for GetIt dependency injection with comprehensive support for all registration types and async dependencies.
β¨ Features
- π Optimized Lazy Loading: Efficient dependency registration with automatic instance creation
- π Multiple Registration Types: Support for factory, singleton, and lazy singleton patterns
- β‘ Async Support: Full support for asynchronous dependency initialization
- π― Performance Optimized: Minimal overhead with smart registration checking
- π‘οΈ Type Safe: Full type safety with generic methods
- π§ͺ Well Tested: 100% test coverage ensuring reliability
π¦ Installation
Add this to your package's pubspec.yaml
file:
dependencies:
get_it_lazyload: ^0.0.3
get_it: ^8.2.0
Then run:
flutter pub get
π Quick Start
import 'package:get_it/get_it.dart';
import 'package:get_it_lazyload/get_it_lazyload.dart';
final getIt = GetIt.instance;
// Register a service with automatic lazy loading
final service = getIt.getOrRegister<MyService>(
() => MyService(),
RegisterAs.singleton
);
π Usage
Basic Usage
import 'package:get_it/get_it.dart';
import 'package:get_it_lazyload/get_it_lazyload.dart';
final getIt = GetIt.instance;
// Register a service with automatic lazy loading
getIt.getOrRegister<MyService>(() => MyService(), RegisterAs.singleton);
// Get the service (will be created if not registered)
final service = getIt.get<MyService>();
Lazy Loading Pattern for Use Cases and Repositories
The main benefit of this package is avoiding eager registration of dependencies at app startup. Instead, dependencies are loaded and registered only when they're actually required:
// UseCase with Factory pattern (creates new instance each time)
class AnonymousAuthUseCase {
final AuthRepository _repository;
AnonymousAuthUseCase(this._repository);
Future<FirebaseUserModel> execute() {
return _repository.signInAnonymously();
}
static AnonymousAuthUseCase get() {
return GetIt.instance.getOrRegister<AnonymousAuthUseCase>(
() => AnonymousAuthUseCase(AuthRepository.get()),
RegisterAs.factory);
}
}
// Repository with LazySingleton pattern (reuses instance)
class AuthRepository {
final DatabaseService _database;
AuthRepository(this._database);
Future<FirebaseUserModel> signInAnonymously() async {
return _database.createAnonymousUser();
}
static AuthRepository get() {
return GetIt.instance.getOrRegister<AuthRepository>(
() => AuthRepository(DatabaseService.get()),
RegisterAs.lazySingleton);
}
}
// Service with Singleton pattern (created immediately when first accessed)
class DatabaseService {
static DatabaseService get() {
return GetIt.instance.getOrRegister<DatabaseService>(
() => DatabaseService(),
RegisterAs.singleton);
}
}
Benefits of this pattern:
- β Dependencies are created only when needed
- β No eager registration at app startup
- β Automatic dependency resolution
- β Clean separation of concerns
- β Easy to test and mock
Registration Types
Singleton
Creates instance immediately and reuses it:
getIt.getOrRegister<ConfigService>(
() => ConfigService(),
RegisterAs.singleton
);
Factory
Creates new instance each time:
getIt.getOrRegister<DataModel>(
() => DataModel(),
RegisterAs.factory
);
Lazy Singleton
Creates instance on first use, then reuses it:
getIt.getOrRegister<ExpensiveService>(
() => ExpensiveService(),
RegisterAs.lazySingleton
);
Async Dependencies
Async Factory
final service = await getIt.getOrRegisterAsync<AsyncService>(
() async => await AsyncService.initialize(),
RegisterAs.factoryAsync
);
Async Lazy Singleton
final service = await getIt.getOrRegisterAsync<AsyncService>(
() async => await AsyncService.initialize(),
RegisterAs.lazySingletonAsync
);
Async Singleton
final service = await getIt.getOrRegisterAsync<AsyncService>(
() async => await AsyncService.initialize(),
RegisterAs.singletonAsync
);
Convenience Methods
For common use cases, you can use these convenience methods:
// Factory registration
getIt.getOrRegisterFactory<DataModel>(() => DataModel());
// Lazy singleton registration
getIt.getOrRegisterLazySingleton<Service>(() => Service());
// Singleton registration
getIt.getOrRegisterSingleton<Config>(() => Config());
// Async variants
await getIt.getOrRegisterFactoryAsync<AsyncService>(
() async => await AsyncService.initialize()
);
await getIt.getOrRegisterLazySingletonAsync<AsyncService>(
() async => await AsyncService.initialize()
);
await getIt.getOrRegisterSingletonAsync<AsyncService>(
() async => await AsyncService.initialize()
);
π API Reference
RegisterAs Enum
RegisterAs.singleton
- Creates instance immediately and reuses itRegisterAs.factory
- Creates new instance each timeRegisterAs.lazySingleton
- Creates instance on first use, then reuses itRegisterAs.factoryAsync
- Creates new async instance each timeRegisterAs.lazySingletonAsync
- Creates async instance on first use, then reuses itRegisterAs.singletonAsync
- Creates async instance immediately and reuses it
GetItExtension Methods
getOrRegister<T>()
- Gets or registers a dependencygetOrRegisterAsync<T>()
- Gets or registers an async dependencygetOrRegisterFactory<T>()
- Gets or registers as factorygetOrRegisterLazySingleton<T>()
- Gets or registers as lazy singletongetOrRegisterSingleton<T>()
- Gets or registers as singletongetOrRegisterFactoryAsync<T>()
- Gets or registers as async factorygetOrRegisterLazySingletonAsync<T>()
- Gets or registers as async lazy singletongetOrRegisterSingletonAsync<T>()
- Gets or registers as async singleton
π Performance Benefits
- Single Registration Check: Only checks if dependency is registered once per call
- Optimized Registration: Direct function registration without extra wrapping
- Lazy Initialization: Dependencies are only created when needed
- Memory Efficient: Reuses instances where appropriate
- Startup Performance: No eager registration means faster app startup
β οΈ Important Notes
Async Registration Behavior
Due to GetIt's internal implementation of async registrations, there are some limitations to be aware of:
- Async Factory: Works as expected - creates new instances each time
- Async Lazy Singleton: May create new instances on subsequent calls due to GetIt's async registration behavior
- Async Singleton: Works as expected - creates instance once and reuses it
For the most reliable behavior with async dependencies, consider using RegisterAs.singletonAsync
when you need consistent instance reuse.
Best Practices
- Use sync registration methods when possible for better performance
- Reserve async registration for dependencies that truly require async initialization
- Test your dependency injection setup thoroughly, especially with async services
- Consider using
RegisterAs.singletonAsync
for services that should be shared across your app - Use the lazy loading pattern for UseCases and Repositories to avoid eager registration
- Only register core dependencies (like config) at app startup
π± Example
Check out the example app for a complete working demonstration of the lazy loading pattern.
import 'package:get_it/get_it.dart';
import 'package:get_it_lazyload/get_it_lazyload.dart';
class MyApp {
static void setupDependencies() {
final getIt = GetIt.instance;
// Only register core dependencies that are needed immediately
getIt.getOrRegister<ConfigService>(
() => ConfigService(),
RegisterAs.singleton
);
// Other dependencies will be registered lazily when first accessed
// No need to register AuthRepository, AnonymousAuthUseCase, etc. here
}
}
π§ͺ Testing
The package includes comprehensive tests with 100% coverage:
# Run tests
flutter test
# Run tests with coverage
flutter test --coverage
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
π License
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments
- Built on top of the excellent GetIt package
- Inspired by clean architecture principles and dependency injection best practices
- Community feedback and contributions
π Package Health
- β Test Coverage: 100%
- β Static Analysis: Passing
- β Documentation: Complete
- β Examples: Included
- β License: MIT
- β Platform Support: Flutter (iOS, Android, Web, Desktop)
Libraries
- get_it_lazyload
- A Flutter package providing optimized lazy loading extensions for GetIt dependency injection.