ZeroProcess
ZeroProcess

Reputation: 1221

How to use dependecy injection in flutter?

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

Answers (6)

Christian Findlay
Christian Findlay

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

Filip Jerga
Filip Jerga

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

Jon
Jon

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

HoppedUpDev
HoppedUpDev

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

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

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

Hadrien Lejard
Hadrien Lejard

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

Related Questions