Dependency Injection with Flutter

You know dependency injection? You love dependency injection!
Unfortunately, Flutter don’t provide any built-in DI feature.

For this, I created last year the flutter_catalyst package with is a port of the catalyst package which is only supported for D…


This content originally appeared on DEV Community and was authored by Julian Finkler

You know dependency injection? You love dependency injection!
Unfortunately, Flutter don't provide any built-in DI feature.

For this, I created last year the flutter_catalyst package with is a port of the catalyst package which is only supported for Dart native.

flutter_catalyst was a good starting point for me to implement DI in my Flutter apps but in large projects it's a mess to configure.

In the last two months I created a new package catalyst_builder which supports all platforms and is easy to configure.

This package uses the build_runner which performs tasks when you run it.
catalyst_builder has a build_runner task that reads annotations from your dart files and generate a service provider for DI.

Setup

Run flutter pub add catalyst_builder or add the package to your pubspec.yaml

# pubspec.yaml
dependencies:
  catalyst_builder: ^1.0.1

Since we use the build_runner you need to add this to your dev_dependencies:

# pubspec.yaml

dev_dependencies:
  build_runner: ^2.0.4

Create a build.yaml beside your pubspec.yaml. This file contains the configuration for the service provider (output file name and provider class name)

targets:
  $default:
    auto_apply_builders: true
    builders:
      catalyst_builder|buildServiceProvider:
        options:
          providerClassName: 'AppServiceProvider'
          outputName: 'app_service_provider.dart'

Run flutter pub get to install the packages

Now run flutter pub pub run build_runner watch --delete-conflicting-outputs which watches for changes and create the service provider dart file

Usage

You can declare every class as a service with the @Service annotation from the catalyst_builder package:

@Service()
class MyService {
   final String username = 'TestUser';
}

Ensure that flutter pub pub run build_runner watch --delete-conflicting-outputs is running. You should see now a app_service_provider.dart file that you can include in your project.

Create the service provider and retrieve the service from it:

var myProvider = AppServiceProvider();
myProvider.boot(); // This is important

var myService = myProvider.resolve<MyService>();
//  also works: MyService myService = myProvider.resolve();
print(myService.username); // prints TestUser

Thats all for a simple service.

Nested services a.k.a. Dependency Injection

In the real world you've services that depend on other services that depend on configuration parameters etc.

catalyst_builder also supports this scenario:

@Service()
class ServiceA {}

@Service()
class ServiceB {
    final ServiceA serviceA;
    ServiceB(this.ServiceA);
}

class ServiceC {} 

@Service()
class ServiceD {
    final ServiceC serviceC;
    ServiceD(@Parameter('otherService') this.ServiceC);
}


void main() {
    var myProvider = AppServiceProvider();
    myProvider.boot();

    // This works:
    var serviceB = myProvider.resolve<ServiceB>();

    // This not because ServiceC is not known as a service:
    var serviceD = myProvider.resolve<ServiceD>();

    // But this works, because the provider contains a 
    // parameter with the same name as the required argument:
    myProvider.parameters['serviceC'] = ServiceC();
    var serviceD = myProvider.resolve<ServiceD>();

    // This also works, because the provider contains a 
    // parameter with the name which is given in the 
    // Parameter annotation.
    myProvider.parameters['otherService'] = ServiceC();
    var serviceD = myProvider.resolve<ServiceD>();
}

Service lifetime

By default, all services are singeltons. You will get the same instance everytime you call resolve<T>.

You can specify the lifetime with the lifetime argument in the @Service annotation:

/// Transient services are always recreated
@Service(lifetime: ServiceLifetime.transient)
class TransientService {}

/// Default is singleton
@Service(lifetime: ServiceLifetime.singleton)
class SingletonService {}

Code Against Interfaces, Not Implementations.

Every programmer would tell you that you shouldn't depend on implementations but interfaces.

Also this is possible with the exposeAs Property in the @Service annotation. Expose as will return the implementation if you request the type that you provide as exposeAs. This also works for nested services.

// interface
abstract class BaseService {}

// implementation
@Service(exposeAs: BaseService)
class MyService implements BaseService {}

Preloading services

Some services are background services (connectivity checks for example).
Decorate this services with @Preload() to create a instance of the service while boot()-ing the provider.

@Service()
@Preload()
class MyService {
  MyService(){
    print('Service was created');
  }
}

void main() {
  ServiceProvider provider;
  provider.boot(); // prints "Service was created" 
  provider.resolve<MyService>(); // Nothing printed
}

Flutter specific tips:

  • Screens (widgets) should be always transient services.
  • You can use resolve<T> in the router:
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: {
        '/': (_) => container.resolve<HomeScreen>(),
      },
    );
  }
}

Hope you like and use the package ;-)


This content originally appeared on DEV Community and was authored by Julian Finkler


Print Share Comment Cite Upload Translate Updates
APA

Julian Finkler | Sciencx (2021-06-18T05:57:01+00:00) Dependency Injection with Flutter. Retrieved from https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/

MLA
" » Dependency Injection with Flutter." Julian Finkler | Sciencx - Friday June 18, 2021, https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/
HARVARD
Julian Finkler | Sciencx Friday June 18, 2021 » Dependency Injection with Flutter., viewed ,<https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/>
VANCOUVER
Julian Finkler | Sciencx - » Dependency Injection with Flutter. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/
CHICAGO
" » Dependency Injection with Flutter." Julian Finkler | Sciencx - Accessed . https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/
IEEE
" » Dependency Injection with Flutter." Julian Finkler | Sciencx [Online]. Available: https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/. [Accessed: ]
rf:citation
» Dependency Injection with Flutter | Julian Finkler | Sciencx | https://www.scien.cx/2021/06/18/dependency-injection-with-flutter/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.