Dependency Injection In Flutter With Inherited Widget — Stack Secrets

Sovit Poudel
Stack Secrets
Published in
3 min readMay 26, 2019

In this post, we will introduce the concept of dependency injection and learn to setup dependency injection in Flutter with inherited widget.

Introduction To Dependency Injection

Dependency Injection is a technique for resolving object dependencies during class initialization. It allows the creation of dependent objects outside of a class.

This technique allows us to write clean code where we can program against interfaces rather than concrete class types. It also enables to write testable codes.

Dependency Injection

For example, in the code below, class A requires an object of type B in it’s constructor.

class A {
B b;
A(B b) {
}
}

abstract class B {
doSomething();
}

class C implements B {
doSomething() {

}

class D implements B {
doSomething() {

}
}
}

The class B is an abstract class which acts as an interface. Class C could be it’s real implementation and D be it’s implementation for testing purpose.

Depending upon whether we are running unit tests or running applications, class A’s constructor should receive a different instance of C or D. If the app is under test mode, you want to pass an object of type D in the A’s constructor. Otherwise, you want to pass an object of type C.

A dependency injection technique allows to resolve such dependencies in an application during runtime.

Dependency Injection In Flutter

The steps to make use of the dependency manager in our Flutter app is going to be like this:

  • Create a dependency manager.
  • Add all the dependencies for the application in this manager.
  • Initialize the dependency manager when the application starts.
  • Use Inherited Widget to keep this manager in app’s state.
  • Get access to the dependency manager object via the app’s state.
  • Resolve dependencies during runtime via the injector object.

For the purpose of this post, we will make use of a dependency injection plugin called “ flutter_simple_dependency_injection

Setup Dependency Manager

Once you have added the package into your Flutter application, create a base class for dependency manager.

import ‘package:flutter_simple_dependency_injection/injector.dart’;

abstract class DependencyManagerBase {
Injector injector;
}

We are making this class abstract in order to be able to create separate types of dependency manager based on test, development or production environments.

Now, add a concrete implementation for this manager.

class DependencyManager implements DependencyManagerBase {

@override
Injector injector;

DependencyManager() {
injector = Injector.getInjector();
// Add your dependencies here
injector.map<B>((i) => C());
}
}

We have initialized Injector in the constructor of the DependencyManager. The Injector object holds the list of all dependencies in your application.

Now we need to make use of the dependency manager. For this purpose, we will use the Inherited Widget.

Using Inherited Widget For Dependency Injection

If you are completely new to Inherited Widget, you should check out this article first.

class AppStateProvider extends InheritedWidget {
final AppState state;
final DependencyManagerBase diBase;

AppStateProvider(this.diBase, {Key key, Widget child})
: state = new AppState(diBase),
super(key: key, child: child){
state.init();
}

@override
bool updateShouldNotify(_) => false;

static AppState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(AppStateProvider)
as AppStateProvider)
.state;
}
}

Here the AppStateProvider class is an InheritedWidget which manages the app state. The dependency manager is passed onto the AppState class.

Once you have the InheritedWidget setup, you can initialize the dependency manager like this:

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AppStateProvider(
DependencyManager(),//initialize the dependency manager
child: MyHomePage(),
);
}
}

This allows us to get the AppState anywhere in the application by calling the static method “ of “.

final appState = AppStateProvider.of(context);

Finally, you can access the injector object from anywhere in the application via the AppState object.

var diManager = widget.appState.diBase;
var a = A(diManager.injector.get<B>());

Originally published at http://stacksecrets.com on May 26, 2019.

--

--