Reputation: 1221
I wan to use di. in flutter and I add this https://pub.dartlang.org/packages/di packages my project and I started to read this https://webdev.dartlang.org/angular/guide/dependency-injection article, but I don't fully understand.
So it's ok: use @Injectable() annotation on services class(e.g: MyServices), but how to inject other class? For example I would like to similar:
class MyClass{
//some variable
var asd = MyService.asd; //need inject var.
//maybe use injector.get(MyService).asd;
//but how add injector? (I don't add across constructor)
MyService.oneMethod;//need inject method
}
main(){
var injector = new ModuleInjector([new Module()
..bind(MyService)
]);
}
The point is, I don't want to use a constructor. I want to directly use injector. This is possible in flutter/dart?
Upvotes: 4
Views: 9830
Reputation: 7672
This package ioc_container is a Dart Ioc Container. Technically, it's not an injector because it doesn't automate injection with anything like reflection. However, it does simplify and organize the process of injecting dependencies within your factories. Here is the code.
Code here
import 'package:meta/meta.dart';
class ServiceDefinition<T> {
bool isSingleton;
T Function(IocContainer container) factory;
ServiceDefinition(this.isSingleton, this.factory);
}
class IocContainer {
@visibleForTesting
final Map<Type, ServiceDefinition> serviceDefinitionsByType;
@visibleForTesting
final Map<Type, Object> singletons;
IocContainer(this.serviceDefinitionsByType, this.singletons);
///Get an instance of your dependency
T get<T>() => singletons.containsKey(T)
? singletons[T] as T
: serviceDefinitionsByType.containsKey(T)
? (serviceDefinitionsByType[T]!.isSingleton
? singletons.putIfAbsent(
T,
() =>
serviceDefinitionsByType[T]!.factory(this) as Object) as T
: serviceDefinitionsByType[T]!.factory(this))
: throw Exception('Service not found');
}
///A builder for creating an [IocContainer].
class IocContainerBuilder {
final Map<Type, ServiceDefinition> _serviceDefinitionsByType = {};
///Throw an error if a service is added more than once. Set this to true when
///you want to add mocks to set of services for a test.
final bool allowOverrides;
IocContainerBuilder({this.allowOverrides = false});
///Add a factory to the container.
void addServiceDefinition<T>(
///Add a factory and whether or not this service is a singleton
ServiceDefinition<T> serviceDefinition) {
if (_serviceDefinitionsByType.containsKey(T)) {
if (allowOverrides) {
_serviceDefinitionsByType.remove(T);
} else {
throw Exception('Service already exists');
}
}
_serviceDefinitionsByType.putIfAbsent(T, () => serviceDefinition);
}
///Create an [IocContainer] from the [IocContainerBuilder].
///This will create an instance of each singleton service and store it
///in an immutable list unless you specify [isLazy] as true.
IocContainer toContainer(
{
///If this is true the services will be created when they are requested
///and this container will not technically be immutable.
bool isLazy = false}) {
if (!isLazy) {
final singletons = <Type, Object>{};
final tempContainer = IocContainer(_serviceDefinitionsByType, singletons);
_serviceDefinitionsByType.forEach((type, serviceDefinition) {
if (serviceDefinition.isSingleton) {
singletons.putIfAbsent(
type, () => serviceDefinition.factory(tempContainer));
}
});
return IocContainer(
Map<Type, ServiceDefinition>.unmodifiable(_serviceDefinitionsByType),
Map<Type, Object>.unmodifiable(singletons));
}
return IocContainer(
Map<Type, ServiceDefinition>.unmodifiable(_serviceDefinitionsByType),
<Type, Object>{});
}
}
extension Extensions on IocContainerBuilder {
///Add a singleton object dependency to the container.
void addSingletonService<T>(T service) =>
addServiceDefinition(ServiceDefinition(true, (i) => service));
void addSingleton<T>(T Function(IocContainer container) factory) =>
addServiceDefinition(ServiceDefinition(true, factory));
void add<T>(T Function(IocContainer container) factory) =>
addServiceDefinition(ServiceDefinition(false, factory));
}
Upvotes: 0
Reputation: 75
Hello what about something like this? Very simple implementation, Injector itself is singleton and also added classes into it. Of course can be extended very easily. If you are looking for something more sophisticated check this package: https://pub.dartlang.org/packages/flutter_simple_dependency_injection
void main() {
Injector injector = Injector();
injector.add(() => Person('Filip'));
injector.add(() => City('New York'));
Person person = injector.get<Person>();
City city = injector.get<City>();
print(person.name);
print(city.name);
}
class Person {
String name;
Person(this.name);
}
class City {
String name;
City(this.name);
}
typedef T CreateInstanceFn<T>();
class Injector {
static final Injector _singleton = Injector._internal();
final _factories = Map<String, dynamic>();
factory Injector() {
return _singleton;
}
Injector._internal();
String _generateKey<T>(T type) {
return '${type.toString()}_instance';
}
void add<T>(CreateInstanceFn<T> createInstance) {
final typeKey = _generateKey(T);
_factories[typeKey] = createInstance();
}
T get<T>() {
final typeKey = _generateKey(T);
T instance = _factories[typeKey];
if (instance == null) {
print('Cannot find instance for type $typeKey');
}
return instance;
}
}
Upvotes: 1
Reputation: 4295
I was facing the same issue here so I created a dart package specifically for Flutter. It relies on factory methods rather than the mirrors api so it works in flutter. While still using a familiar IOC pattern. Hope this helps!
https://pub.dartlang.org/packages/flutter_simple_dependency_injection
import 'package:flutter_simple_dependency_injection/injector.dart';
void main() {
final injector = Injector.getInjector();
injector.map(Logger, (i) => new Logger(), isSingleton: true);
injector.map(String, (i) => "https://api.com/", key: "apiUrl");
injector.map(SomeService, (i) => new SomeService(i.get(Logger), i.get(String, "apiUrl")));
injector.get(SomeService).doSomething();
// passing in the [SomeService] as a generic parameter strongly types the return object.
injector.get<SomeService>(SomeService).doSomething();
}
class Logger {
void log(String message) => print(message);
}
class SomeService {
final Logger _logger;
final String _apiUrl;
SomeService(this._logger, this._apiUrl);
void doSomething() {
_logger.log("Doing something with the api at '$_apiUrl'");
}
}
Upvotes: 0
Reputation: 71
There is a Flutter-compatible dependency injection framework that Google recently open-sourced. It is available here: https://github.com/google/inject.dart
This project provides static compile-time dependency injection, rather than relying on reflection to inject dependencies at run-time. If you are familiar with Dagger, it appears to be quite similar.
It's worth noting - this is not an official Google or Dart team project. At the time of writing, there is little documentation and it is currently considered a developer preview.
Upvotes: 6
Reputation: 657078
Angulars DI package can't be used independent of Angular.
The di package is quite outdated and depends on dart:mirrors
which isn't available in Flutter
There seems to be a new DI package work in progress which is supposed to replace Angulars built-in DI and should also be useable standalone in Flutter or server-side applications, but there is no pre-release or source code available yet.
update
The announced DI package was delayed indefinitely.
Upvotes: 5
Reputation: 5894
If you want to use a class as a Singleton, from what I saw, the common usecase is to use a factory constructor.
How do you build a Singleton in Dart?
Never had to use any dependency injection system with Flutter for now.
Upvotes: 1