Your Second Flutter App

Nov 30 2021 Dart 2.13, Flutter 2.2.3, Visual Studio Code

Part 1: Parse Network Data

9. Use Dependency Injection

Episode complete

Play next episode

Next
About this episode
See versions
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 8. Parse Domains Next episode: 10. Conclusion

This video Use Dependency Injection was last updated on Nov 30 2021

Earlier, when introducing the model and repository, we discussed app architecture. A key aspect of architecture is how your app components and classes are connected to one another, or depend on one another.

For example, here we have a Garage class that has a strong reference to a car. This is strongly coupled. This means, if anything changes with the car’s implementation, the garage may need to be changed as well. This is strong coupling.

To avoid this problem, we define abstract classes to get around this problem. In our case, we’ll define a car as a type of vehicle and code against the the vehicle versus coding against the car. That way if the car’s implementation changes, the garage won’t be affected. This is loose coupling.

Dependency injection is used alongside abstract classes to help achieve loose coupling. In our app, the course repository property is created directly inside the courses controller class. That introduces a strong coupling between the controller and courses repository.

First, we should abstract our course repository to an abstract type. This makes our app adaptable and more importantly, capable of dependency injection.

Now we can simply pass in a course repository to the courses controller. That way, the user of the controller can decide what concrete type of repository to pass to the controller, and the controller is no longer responsible for creating it. The controller only knows about the repository interface, and can work with any kind of repository.

For testing your controller, that would let you pass a test repository to the controller instead of using the CoursesRepository that makes real network calls. Passing in the property using the constructor is a form of dependency injection, since you’re passing or injecting the dependency into the controller instead of creating it inside the controller.

Like with our architecture discussion, we won’t go too deep into the theory here. This episode is just meant to expose you to the idea of dependency injection, so that when you come across it again someday, you’ll have some background on what it means and why it is used.

To get started, open your project in progress or download the starter project. With your project open, open the course_controller.dart file in the courses folder located in the ui folder.

So here we are setting repository directly in the controller. This isn’t a form of dependency injection as we want to pass in the repository instead. Update the property to the following:

final Repository _repository;

Now lets delete the unneeded import. Now we need to set the repository. Add a constructor for the controller.

CoursesController(this._repository);

The constructor lets you inject the repository into the controller. The controller no longer aware of a specific repository type, and now only knows about the interface of a repository. Now we need to inject a course repository. Open up courses_page.dart. Add the following:

final _controller = CoursesController(CourseRepository());

And then add the import.

import '../../repository/course_repository.dart';

Re-run the app to make sure all is good. It looks and behaves exactly the same except this time, you are injecting the repository instead of hard coding it. It’s a small change, but you’ve made the code flexible to change and easier to test.