Настройка Dependency Injection (GetIt) у Flutter-додатку
GetIt — service locator для Dart/Flutter, де-факто стандарт для DI в проектах, де не потрібна кодогенерація. Принцип простий: реєструєш залежності один раз при старті додатку, запитуєш в будь-якому місці через GetIt.instance<T>() або скорочення sl<T>().
Чому саме GetIt, а не щось інше
provider та Riverpod — це State Management з DI як побічним ефектом. GetIt — чистий service locator без Flutter-залежностей: його можна використовувати в domain-шарі без BuildContext. Для Clean Architecture, де domain-шар нічого не знає про Flutter, це принципово.
Конструктор GetIt підтримує три режими реєстрації:
-
registerSingleton<T>— створює відразу при реєстрації, живе весь час роботи додатку -
registerLazySingleton<T>— створює при першому звращенні, потім повертає той самий інстанс -
registerFactory<T>— створює новий інстанс при кожному звращенні
На практиці: ApiService, DatabaseHelper, SharedPreferences-обертка — registerLazySingleton. ViewModel або BLoC, якщо їх створює GetIt (рідко) — registerFactory. Частіше BLoC створюється через BlocProvider, а GetIt тримає лише інфраструктурний шар.
Типична помилка при ініціалізації
// Неправильно — синхронна реєстрація асинхронної залежності
sl.registerLazySingleton<DatabaseHelper>(() => DatabaseHelper()..init());
// Правильно — async init через registerSingletonAsync
sl.registerSingletonAsync<DatabaseHelper>(() async {
final db = DatabaseHelper();
await db.init();
return db;
});
// І дочекатися готовності перед runApp:
await sl.allReady();
Якщо не використовувати registerSingletonAsync + allReady(), DatabaseHelper може бути запрошений до завершення асинхронної ініціалізації — крэш на старті з StateError: Singleton is not ready yet.
Організація injection_container.dart
Стандартна практика — один файл injection_container.dart (або di/) з функцією initDependencies():
Future<void> initDependencies() async {
// External
final sharedPrefs = await SharedPreferences.getInstance();
sl.registerLazySingleton(() => sharedPrefs);
sl.registerLazySingleton(() => http.Client());
// Data sources
sl.registerLazySingleton<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImpl(sl()),
);
// Repositories
sl.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(sl()),
);
// Use cases
sl.registerLazySingleton(() => LoginUseCase(sl()));
// BLoCs — якщо створюються через GetIt
sl.registerFactory(() => AuthBloc(loginUseCase: sl()));
}
Реєструємо в порядку залежностей знизу вверх: спочатку зовнішні залежності, потім data sources, репозиторії, use cases, нарешті — presentation шар.
GetIt + flutter_modular або feature-based DI
На великих проектах один injection_container.dart перетворюється в 500 рядків. Рішення: розбити по фічам. Кожен feature-модуль реєструє свої залежності через окрему функцію initAuthDependencies(), initProfileDependencies() — викликаються з головного initDependencies().
Що входить у настройку
Аналізуємо поточну архітектуру проекту → визначаємо шари та залежності → налаштовуємо injection_container з коректними часами життя → прописуємо async-ініціалізацію для БД та Storage → покриваємо реєстрацію unit-тестами через mock-підмену у тестовому setUp.
Робота займає 1–2 дні залежно від розміру проекту та кількості існуючих залежностей.







