Get It - Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App. Maintainer: @escamoteur

Related tags

Templates get_it
Overview

Flutter Community: get_it

❤️ Sponsor Buy Me A Coffee

get_it

This is a simple Service Locator for Dart and Flutter projects with some additional goodies highly inspired by Splat. It can be used instead of InheritedWidget or Provider to access objects e.g. from your UI.

Typical usage:

  • Accessing service objects like REST API clients or databases so that they easily can be mocked.
  • Accessing View/AppModels/Managers/BLoCs from Flutter Views

V7.0 has some breaking changes Check please check the release notes to see what's new.

Why GetIt

As your App grows, at some point you will need to put your app's logic in classes that are separated from your Widgets. Keeping your widgets from having direct dependencies makes your code better organized and easier to test and maintain. But now you need a way to access these objects from your UI code. When I came to Flutter from the .Net world, the only way to do this was the use of InheritedWidgets. I found the way to use them by wrapping them in a StatefulWidget; quite cumbersome and has problems working consistently. Also:

  • I missed the ability to easily switch the implementation for a mocked version without changing the UI.
  • The fact that you need a BuildContext to access your objects made it inaccessible from the Business layer.

Accessing an object from anywhere in an App can be done by other ways, but:

  • If you use a Singleton you can't easily switch the implementation out for a mock version in tests
  • IoC containers for Dependency Injections offers similar functionality, but with the cost of slow start-up time and less readability because you don't know where the magically injected object come from. Most IoC libs rely on reflection they cannot be ported to Flutter.

As I was used to use the Service Locator Splat from .Net, I decided to port it to Dart. Since then, more features have been added.

If you are not familiar with the concept of Service Locators, it's a way to decouple the interface (abstract base class) from a concrete implementation, and at the same time allows to access the concrete implementation from everywhere in your App over the interface. I can only highly recommend to read this classic article by from Martin Fowler Inversion of Control Containers and the Dependency Injection pattern.

GetIt is:

  • Extremely fast (O(1))
  • Easy to learn/use
  • Doesn't clutter your UI tree with special Widgets to access your data like provider or Redux does.

The get_it_mixin

GetIt isn't a state management solution! It's a locator for your objects so you need some other way to notify your UI about changes like Streams or ValueNotifiers. But together with the get_it_mixin it gets a full featured easy state management solution that integrates with the Objects registered in get_it

Getting Started

At your start-up you register all the objects you want to access later like this:

final getIt = GetIt.instance;

void setup() {
  getIt.registerSingleton<AppModel>(AppModel());

// Alternatively you could write it if you don't like global variables
  GetIt.I.registerSingleton<AppModel>(AppModel());
}

After that you can access your AppModel class from anywhere like this:

MaterialButton(
  child: Text("Update"),
  onPressed: getIt<AppModel>().update   // given that your AppModel has a method update
),

You can find here a detailed blog post on how to use GetIt

GetIt in Detail

As Dart supports global (or euphemistic ambient) variables I often assign my GetIt instance to a global variable to make the access to it as easy as possible

Although the approach with a global variable worked well, it has its limitations if you want to use GetIt across multiple packages. Therefore GetIt itself is a singleton and the default way to access an instance of GetIt is to call:

GetIt getIt = GetIt.instance;

//There is also a shortcut (if you don't like it just ignore it):
GetIt getIt = GetIt.I;

Through this any call to instance in any package of a project will get the same instance of GetIt. I still recommend just to assign the instance to a global variable in your project as it is more convenient and doesn't harm (Also it allows you to give your service locator your own name).

GetIt getIt = GetIt.instance;

You can use any name you want which makes Brian 😃 happy like (sl, backend, services...) ;-)

Before you can access your objects you have to register them within GetIt typically direct in your start-up code.

getIt.registerSingleton<AppModel>(AppModelImplementation());
getIt.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());

// if you want to work just with the singleton:
GetIt.instance.registerSingleton<AppModel>(AppModelImplementation());
GetIt.I.registerLazySingleton<RESTAPI>(() =>RestAPIImplementation());

/// `AppModel` and `RESTAPI` are both abstract base classes in this example

To access the registered objects call get<Type>() on your GetIt instance

var myAppModel = getIt.get<AppModel>();

Alternatively as GetIt is a callable class depending on the name you choose for your GetIt instance you can use the shorter version:

var myAppModel = getIt<AppModel>();

// as Singleton:
var myAppModel = GetIt.instance<AppModel>();
var myAppModel = GetIt.I<AppModel>();

Different ways of registration

GetIt offers different ways how objects are registered that effect the lifetime of this objects.

Factory

void registerFactory<T>(FactoryFunc<T> func)

You have to pass a factory function func that returns an NEW instance of an implementation of T. Each time you call get<T>() you will get a new instance returned. How to pass parameters to a factory you can find here

Singleton & LazySingleton

Although I always would recommend using an abstract base class as registration type so that you can vary the implementations you don't have to do this. You can also register concrete types.

void registerSingleton<T>(T instance)

You have to pass an instance of T or a derived class of T that you will always get returned on a call to get<T>().

As creating this instance can be time consuming at app start-up you can shift the creation to the time the object is the first time requested with:

void registerLazySingleton<T>(FactoryFunc<T> func)

You have to pass a factory function func that returns an instance of an implementation of T. Only the first time you call get<T>() this factory function will be called to create a new instance. After that you will always get the same instance returned.

Overwriting registrations

If you try to register a type more than once you will fail with an assertion in debug mode because normally this is not needed and probably a bug. If you really have to overwrite a registration, then you can by setting the property allowReassignment==true.

Testing if a Singleton is already registered

You can check if a certain Type or instance is already registered in GetIt with:

 /// Tests if an [instance] of an object or aType [T] or a name [instanceName]
 /// is registered inside GetIt
 bool isRegistered<T>({Object instance, String instanceName});

Unregistering Singletons or Factories

If you need to you can also unregister your registered singletons and factories and pass a optional disposingFunction for clean-up.

/// Unregister an [instance] of an object or a factory/singleton by Type [T] or by name [instanceName]
/// if you need to dispose some resources before the reset, you can
/// provide a [disposingFunction]. This function overrides the disposing
/// you might have provided when registering.
void unregister<T>({Object instance,String instanceName, void Function(T) disposingFunction})

Resetting LazySingletons

In some cases you might not want to unregister a LazySingleton but instead to reset its instance so that it gets newly created on the next access to it.

  /// Clears the instance of a lazy singleton,
  /// being able to call the factory function on the next call
  /// of [get] on that type again.
  /// you select the lazy Singleton you want to reset by either providing
  /// an [instance], its registered type [T] or its registration name.
  /// if you need to dispose some resources before the reset, you can
  /// provide a [disposingFunction]. This function overrides the disposing
  /// you might have provided when registering.
void resetLazySingleton<T>({Object instance,
                            String instanceName,
                            void Function(T) disposingFunction})

Resetting GetIt completely

/// Clears all registered types. Handy when writing unit tests
/// If you provided dispose function when registering they will be called
/// [dispose] if `false` it only resets without calling any dispose
/// functions
/// As dispose funcions can be async, you should await this function.
Future<void> reset({bool dispose = true});

Scopes

With V5.0 of GetIt it now supports hierarchical scoping of registration. What does this mean? You can push a new registration scope like you push a new page on the Navigator. Any registration after that will be registered in this new scope. When accessing an object with get GetIt first checks the topmost scope for an registration and then the ones below. This means you can register the same type that was already registered in a lower scope again in a scope above and you will always get the latest registered object.

Imagine an app that can be used with or without a login. On App start-up a DefaultUser object is registered with the abstract type User as singleton. As soon as the user logs in, a new scope is pushed and a new LoggedInUser object again with the User type is registered that allows more functions. For the rest of the App nothing has changed as it still accesses User objects through GetIt. As soon as the user Logs off all you have to do is pop the Scope and automatically the DefaultUser is used again.

Another example could be a shopping basket where you want to ensure that not a cart from a previous session is used again. So at the beginning of a new session you push a new scope and register a new cart object. At the end of the session you pop this scope again.

Scope functions

  /// Creates a new registration scope. If you register types after creating
  /// a new scope they will hide any previous registration of the same type.
  /// Scopes allow you to manage different live times of your Objects.
  /// [scopeName] if you name a scope you can pop all scopes above the named one
  /// by using the name.
  /// [dispose] function that will be called when you pop this scope. The scope
  /// is still valied while it is executed
  /// [init] optional function to register Objects immediately after the new scope is
  /// pushed. This ensures that [onScopeChanged] will be called after their registration
  void pushNewScope({void Function(GetIt getIt)? init,String scopeName, ScopeDisposeFunc dispose});

  /// Disposes all factories/Singletons that have ben registered in this scope
  /// and pops (destroys) the scope so that the previous scope gets active again.
  /// if you provided  dispose functions on registration, they will be called.
  /// if you passed a dispose function when you pushed this scope it will be
  /// calles before the scope is popped.
  /// As dispose funcions can be async, you should await this function.
  Future<void> popScope();

  /// if you have a lot of scopes with names you can pop (see [popScope]) all
  /// scopes above the scope with [name] including that scope
  /// Scopes are poped in order from the top
  /// As dispose funcions can be async, you should await this function.
  /// it no scope with [name] exists, nothing is popped and `false` is returned
  Future<bool> popScopesTill(String name);

  /// Clears all registered types for the current scope
  /// If you provided dispose function when registering they will be called
  /// [dispose] if `false` it only resets without calling any dispose
  /// functions
  /// As dispose funcions can be async, you should await this function.
  Future<void> resetScope({bool dispose = true});

Getting notified about the shadowing state of an object

In some cases it might be helpful to know if an Object gets shadowed by another one e.g. if it has some Stream subscriptions that it want to cancel before the shadowing object creates a new subscription. Also the other way round so that a shadowed Object gets notified when it's "active" again meaning when a shadowing object is removed.

For this a class had to implement the ShadowChangeHandlers interface:

abstract class ShadowChangeHandlers {
  void onGetShadowed(Object shadowing);
  void onLeaveShadow(Object shadowing);
}

When the Object is shadowed its onGetShadowed() method is called with the object that is shadowing it. When this object is removed from GetIt onLeaveShadow() will be called.

Getting notified when a scope change happens

When using scopes with objects that shadow other objects its important to give the UI a chance to rebuild and acquire references to the now active objects. For this you can register an call-back function in GetIt The getit_mixin has a matching rebuiltOnScopeChange method.

  /// Optional call-back that will get call whenever a change in the current scope happens
  /// This can be very helpful to update the UI in such a case to make sure it uses
  /// the correct Objects after a scope change
  void Function(bool pushed)? onScopeChanged;

Disposing Singletons and Scopes

From V5.0 on you can pass a dispose function when registering any Singletons. For this the registration functions have a optional parameter:

DisposingFunc<T> dispose

where DisposingFunc is defined as

typedef DisposingFunc<T> = FutureOr Function(T param);

So you can pass simple or async functions as this parameter. This function is called when you pop or reset the scope or when you reset GetIt completely.

When you push a new scope you can also pass a dispose function that is called when a scope is popped or reset but before the dispose functions of the registered objects is called which mean it can still access the objects that were registered in that scope.

Implementing the Disposable interface

Instead of passing a disposing function on registration or when pushing a Scope from V7.0 on your objects onDispose() method will be called if the object that you register implements the Disposable´interface:

abstract class Disposable {
  FutureOr ondDispose();
}

Asynchronous Factories

If a factory needs to call an async function you can use registerFactoryAsync()

/// [T] type to register
/// [func] factory function for this type
/// [instanceName] if you provide a value here your factory gets registered with that
/// name instead of a type. This should only be necessary if you need to register more
/// than one instance of one type. Its highly not recommended
void registerFactoryAsync<T>(FactoryFuncAsync<T> func, {String instanceName});

To access instances created by such a factory you can't use get() but you have to use getAsync() so that you can await the creation of the requested new instance.

/// Returns an Future of an instance that is created by an async factory or a Singleton that is
/// not ready with its initialization.
Future<T> getAsync<T>([String instanceName]);

Asynchronous Singletons

Additionally you can register asynchronous Singletons which means Singletons that have an initialization that requires async function calls. To be able to control such asynchronous start-up behaviour GetIt supports mechanisms to ensure the correct initialization sequence.

You create an Singleton with an asynchronous creation function

  void registerSingletonAsync<T>(FactoryFuncAsync<T> factoryfunc,
      {String instanceName,
      Iterable<Type> dependsOn,
      bool signalsReady = false});

The difference to a normal Singleton is that you don't pass an existing instance but provide an factory function that returns a Future that completes at the end of factoryFunc and signals that the Singleton is ready to use unless true is passed for signalsReady. (see next chapter) To synchronize with other "async Singletons" you can pass a list of Types in dependsOn that have to be ready before the passed factory is executed.

There are two ways to signal the system that an instance is ready.

Synchronizing asynchronous initializations of Singletons

Often your registered services need to do asynchronous initialization work before they can be used from the rest of the app. As this is such a common task, and its closely related to registration/initialization GetIt supports you here too.

GetIt has the function allReady which returns Future<void> that can be used e.g. with a Flutter FutureBuilder to await that all asynchronous initialization is finished.

  Future<void> allReady({Duration timeout, bool ignorePendingAsyncCreation = false});

There are different approaches how the returned Future can be completed:

Using async Singletons

If you register any async Singletons allReady will complete only after all of them have completed their factory functions. Like:

  class RestService {
    Future<RestService> init() async {
      Future.delayed(Duration(seconds: 1));
      return this;
    }
  }

  final getIt = GetIt.instance;

  /// in your setup function:
  getIt.registerSingletonAsync<ConfigService>(() async {
    final configService = ConfigService();
    await configService.init();
    return configService;
  });

  getIt.registerSingletonAsync<RestService>(() async => RestService().init());
  // here we asume an async factory function `createDbServiceAsync`
  getIt.registerSingletonAsync<DbService>(createDbServiceAsync);


  /// ... in your startup page:
  return FutureBuilder(
      future: getIt.allReady(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return Scaffold(
            body: Center(
              child: Text('The first real Page of your App'),
            ),
          );
        } else {
          return CircularProgressIndicator();
        }
      });

The above example shows you different ways to register async Singletons. The start-up page will display a CircularProgressIndicator until all services have been created.

Solving dependencies

Automatic using dependsOn

In case that this services have to be initialized in a certain order because they depend on that other services are already ready to be used you can use the dependsOn parameter of registerFactoryAsync. If you have a non async Singleton that depends on other Singletons, there is registerSingletonWithDependencies. In the following example, DbService depends on ConfigService, and AppModel depends on ConfigService and RestService

  getIt.registerSingletonAsync<ConfigService>(() async {
    final configService = ConfigService();
    await configService.init();
    return configService;
  });

  getIt.registerSingletonAsync<RestService>(() async => RestService().init());

  getIt.registerSingletonAsync<DbService>(createDbServiceAsync,
      dependsOn: [ConfigService]);

  getIt.registerSingletonWithDependencies<AppModel>(
      () => AppModelImplmentation(),
      dependsOn: [ConfigService, DbService, RestService]);

When using dependsOn you ensure that the registration waits with creating its singleton on the completion of the type defined in dependsOn.

The dependsOn field also accepts InitDependency classes that allow specifying the dependency by type and instanceName.

  getIt.registerSingletonAsync<RestService>(() async => RestService().init(), instanceName:"rest1");

  getIt.registerSingletonWithDependencies<AppModel>(
      () => AppModelImplmentation(),
      dependsOn: [InitDependency(RestService, instanceName:"rest1")]);

Manually signalling the ready state of a Singleton

Sometimes the mechanism of dependsOn might not give you enough control. For this case you can use isReady to wait for a certain singleton:

  /// Returns a Future that completes if the instance of an Singleton, defined by Type [T] or
  /// by name [instanceName] or by passing the an existing [instance], is ready
  /// If you pass a [timeout], an [WaitingTimeOutException] will be thrown if the instance
  /// is not ready in the given time. The Exception contains details on which Singletons are
  /// not ready at that time.
  /// [callee] optional parameter which makes debugging easier. Pass `this` in here.
  Future<void> isReady<T>({
    Object instance,
    String instanceName,
    Duration timeout,
    Object callee,
  });

To signal that a singleton is ready it can use signalReady, provided you have set the optional signalsReady parameter when registering it OR make your registration type implement the empty abstract class WillSignalReady. Otherwise, allReady will wait on a call to signalsReady. No automatic signaling will happen in that case.

/// Typically this is used in this way inside the registered objects init
/// method `GetIt.instance.signalReady(this);`
void signalReady(Object instance);

You can use this to initialize your Singletons without async registration by using a fire and forget async function from your constructors like so:

class ConfigService {
  ConfigService()
  {
    init();
  }
  Future init() async {
    // do your async initialisation...

    GetIt.instance.signalReady(this);
  }
}

Using allReady repeatedly

Even if you already have awaited allReady, the moment you register new async singletons or singletons with dependencies you can use allReady again. This makes especially sense if you uses scopes where every scope needs to get initialized.

Manual triggering allReady (almost deprecated)

By calling signalReady(null) on your GetIt instance the Future you can get from allReady will be completed. This is the most basic way to synchronize your start-up. If you want to do that don't use signalsReady or async Singletons!!! I recommend using one of the other ways because they are more flexible and express your intention more clear.

You can find here a detailed blog post on async factories and startup synchronization

Passing Parameters to factories

In some cases its handy if you could pass changing values to factories when calling get(). For that there are two variants for registering factories:

/// registers a type so that a new instance will be created on each call of [get] on that type based on
/// up to two parameters provided to [get()]
/// [T] type to register
/// [P1] type of  param1
/// [P2] type of  param2
/// if you use only one parameter pass void here
/// [factoryfunc] factory function for this type that accepts two parameters
/// [instanceName] if you provide a value here your factory gets registered with that
/// name instead of a type. This should only be necessary if you need to register more
/// than one instance of one type. Its highly not recommended
///
/// example:
///    getIt.registerFactoryParam<TestClassParam,String,int>((s,i)
///        => TestClassParam(param1:s, param2: i));
///
/// if you only use one parameter:
///
///    getIt.registerFactoryParam<TestClassParam,String,void>((s,_)
///        => TestClassParam(param1:s);
void registerFactoryParam<T,P1,P2>(FactoryFuncParam<T,P1,P2> factoryfunc, {String instanceName});

and

  void registerFactoryParamAsync<T,P1,P2>(FactoryFuncParamAsync<T,P1,P2> factoryfunc, {String instanceName});

The reason why I settled to use two parameters is that I can imagine some scenarios where you might want to register a builder function for Flutter Widgets that need to get passed a BuildContext and some data object.

When accessing these factories you pass the parameters a optional arguments to get():

  var instance = getIt<TestClassParam>(param1: 'abc',param2:3);

These parameters are passed as dynamics (otherwise I would have had add more generic parameters to get()), but they are checked at runtime to be the correct types.

Testing with GetIt

Unit Tests

When you are writing unit tests with GetIt in your App you have two possibilities:

  • Register all the Objects you need inside your unit Tests so that GetIt can provide its objects to the objects that you are testing.
  • Pass your dependent objects into the constructor of your test objects like:
GetIt getIt = GetIt.instance;

class UserManager {
  AppModel appModel;
  DbService dbService;

  UserManager({AppModel appModel, DbService dbService}) {
    this.appModel = appModel ?? getIt.get<AppModel>();
    this.dbService = dbService ?? getIt.get<DbService>();
  }
}

This way you don't need to pass them in the AppModel and dbService inside your App but you can pass them(or a mocked version) in your Unit tests.

Integration Tests

If you have a mocked version of a Service, you can easily switch between that and the real one based on a flag:

  if (testing) {
    getIt.registerSingleton<AppModel>(AppModelMock());
  } else {
    getIt.registerSingleton<AppModel>(AppModelImplementation());
  }

Experts region

Named registration

Ok you have been warned! All registration functions have an optional named parameter instanceName. Providing a name with factory/singleton here registers that instance with that name and a type. Consequently get() has also an optional parameter instanceName to access factories/singletons that were registered by name.

IMPORTANT: Each name must be unique per type.

  abstract class RestService {}
  class RestService1 implements RestService{
    Future<RestService1> init() async {
      Future.delayed(Duration(seconds: 1));
      return this;
    }
  }
  class RestService2 implements RestService{
    Future<RestService2> init() async {
      Future.delayed(Duration(seconds: 1));
      return this;
    }
  }

  getIt.registerSingletonAsync<RestService>(() async => RestService1().init(), instanceName : "restService1");
  getIt.registerSingletonAsync<RestService>(() async => RestService2().init(), instanceName : "restService2");

  getIt.registerSingletonWithDependencies<AppModel>(
      () {
          RestService restService1 = GetIt.I.get<RestService>(instanceName: "restService1");
          return AppModelImplmentation(restService1);
      },
      dependsOn: [InitDependency(RestService, instanceName:"restService1")],
  );

More than one instance of GetIt

While not recommended, you can create your own independent instance of GetItif you don't want to share your locator with some other package or because the physics of your planet demands it :-)

/// To make sure you really know what you are doing
/// you have to first enable this feature:
GetIt myOwnInstance = GetIt.asNewInstance();

This new instance does not share any registrations with the singleton instance.

Acknowledgements

Many thanks to the insightful discussions on the API with Brian Egan and Simon Lightfoot

Comments
  • Provide async variant of pushNewScope.init function.

    Provide async variant of pushNewScope.init function.

    Currently pushNewScope.init is sync, it's inconvenient if you want for example to execute some async call in the init function before scopeChanged is called.

    enhancement waiting for customer response 
    opened by bitsydarel 27
  • ResetLazySingleton is not resetting.

    ResetLazySingleton is not resetting.

    Hello there, I am implementing a login feature using getIt and cubit. So once the user clicks on the login button the desired behaviour is to reset the lazySingleton Logincubit. This is necessary when the login credentials are wrong. The app should be able to restart the auth process afresh.

    I am using get_it: ^6.0.0

    Here is where I add the resetLazySingleton in the UI in the BlocConsumer

       return BlocConsumer<LogInCubit, LogInState>(
                listener: (context, state) => state.when(
                      initial: () {},
                      loading: () {},
                      loaded: () {
                        Navigator.pushNamed(
                          context,
                          AppRouter.otpRoute,
                        );
                      },
                      error: (error) {
                        phoneNumberController.clear();
                        passwordController.clear();
                        locator.resetLazySingleton<LogInCubit>();
                      },
                    ),
    

    and the Login button.

    @override
     Widget build(BuildContext context) {
       final l10n = context.l10n;
       return MaterialButton(
         onPressed: () {
           locator<LogInCubit>().logIn(
             phoneNumber: phoneNumberController,
             password: passwordController,
           );
           locator.resetLazySingleton<LogInCubit>();
         },
    

    Here is where I register my LazySingleton

    GetIt locator = GetIt.instance;
    
    void setUpServiceLocator() {
     // Services
     locator
       ..registerLazySingleton<LogInCubit>(
         () => LogInCubit(
           authService: locator(),
           hiveService: locator(),
         ),
    
    opened by petermusembi69 25
  • Register factories that take parameters

    Register factories that take parameters

    I would like to register factory that takes a parameter and use GetIt to get instance with parameter.

    class SomeSource {
      final String someId;
      SomeSource(this.someId);
    ...
    }
    
    getIt.registerFactory((String someId) => SomeSource (someId));
    
    getIt.get<SomeSource>("someId");
    

    Hope it makes sense. If you want more info I can provide.

    opened by mvarnagiris 25
  • Formatted lines with 80 characters, null crash fix, English fixes

    Formatted lines with 80 characters, null crash fix, English fixes

    In a production app I used get_it and I had a crash with the nullsafety branch. Turns out that isRegistered() calls _findFactoryByNameAndType() which throws an exception because the returned value is null, but is silenced using the bang (!) character.

    So I fixed that and also reformatted the source code to 100 characters per line (it was not formatted it seemed). Also, many English grammatical and pronunciation errors were fixed.

    opened by noordawod 23
  • How to check if instance of a LazySingle is already created inside of getIt?

    How to check if instance of a LazySingle is already created inside of getIt?

    GetIt.I.registerLazySingleton(() => CrosswordManager());

    I tried to check if an object was created by LazySingleton at least one time but I didn't find it. Because I want to reset the object somewhere.

    opened by mgazisalik 19
  • [Feature Request] Get if registered, else, register then get

    [Feature Request] Get if registered, else, register then get

    Hi, I'm looking for a GetIt version of this pseudocode

    var myClass = GetIt.instance.get<MyClass>(orElse: (){
       // automatic registration of the return value of this method.
      return MyClass();
    });
    

    Use case:

    To avoid this Exception instead of using try/catch:

    "Object with name $instanceName is not registered inside GetIt"

    The only potential issue I foresee is how will GetIt know how you want to register this instance.

    opened by ThinkDigitalSoftware 18
  • how can i set state in static method? i get an error which is 'instanceFactory != null': Object/factory

    how can i set state in static method? i get an error which is 'instanceFactory != null': Object/factory

    hi to all. i use foreground_service plugin & stacked(state management lib) & get_it and foreground_service needs a static periodicfunction that i use a static service class in it. But when i use static class with stacked plugin, the app is working but i cant manage the state which in my static class. So how to manage state in static class, how can i use get_it & static class & states together?

    my static service class is:

     @lazySingleton
    class IlanService with ReactiveServiceMixin {
      static IlanService _ilanService;
      factory IlanService() {
        if (_ilanService == null) {
          _ilanService = IlanService._internal();
          return _ilanService;
        } else {
          return _ilanService;
        }
      }
      Ilan _ilan = Ilan();
      Ilan get ilan => _ilan;
      Future<void> updateIlan() async {
      _ilan = await databaseHelper.getIlan(mazagaService.magazaID);
      notifyListeners();
    }
    

    locator.dart:

    import 'package:get_it/get_it.dart';
    import 'package:injectable/injectable.dart';
    import 'locator.config.dart';
    final getIt = GetIt.instance;
    @InjectableInit(
      initializerName: r'$initGetIt', // default
      preferRelativeImports: true, // default
      asExtension: false, // default
    )
    void configureDependencies() => $initGetIt(getIt);
    

    main.dart:

    void main() async{
      configureDependencies();
      WidgetsFlutterBinding.ensureInitialized();
      runApp(MyApp());
    }
    

    myview.dart which has the periodic function fore foreground_service:

    .
    ..
    ...
    import 'package:buybox/app/services/ilan_service.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_foreground_service_plugin/flutter_foreground_service_plugin.dart';
    import 'package:stacked/stacked.dart';
    import 'package:buybox/datamodels/ilan_model.dart';
    IlanService ilanService = IlanService();
    /* if i try final ilanService = getIt<IlanService>(); then i get an error:
    [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: 'package:get_it/get_it_impl.dart': Failed assertion: line 298 pos 9: 'instanceFactory != null': Object/factory with  type IlanService is not registered inside GetIt.
    E/flutter (26306): (Did you accidentally do  GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;
    E/flutter (26306): Did you forget to register it?)
    */
    void periodicTaskFun() {
      FlutterForegroundServicePlugin.executeTask(() async {
      ..
      ..
      ...
      await ilanService.updateIlan();
      await FlutterForegroundServicePlugin.refreshForegroundServiceContent(
        notificationContent: NotificationContent(
          iconName: 'ic_launcher',
          titleText: 'Title Text',
          bodyText: '${DateTime.now()}',
          subText: 'subText',
          color: Colors.red,
        ),
      );
    });
    

    and lastly i added locator.config.dart:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    // **************************************************************************
    // InjectableConfigGenerator
    // **************************************************************************
    import 'package:stacked_services/stacked_services.dart';
    import 'package:get_it/get_it.dart';
    import 'package:injectable/injectable.dart';
    import 'services/fiyat_service.dart';
    import 'services/third_party_services_module.dart';
    /// adds generated dependencies
    /// to the provided [GetIt] instance
    GetIt $initGetIt(
      GetIt get, {
      String environment,
      EnvironmentFilter environmentFilter,
    }) {
      final gh = GetItHelper(get, environment, environmentFilter);
      final thirdPartyServicesModule = _$ThirdPartyServicesModule();
      gh.lazySingleton<IlanService>(() => IlanService());
      // Eager singletons must be registered in the right order
      gh.singleton<DialogService>(thirdPartyServicesModule.dialogService);
      return get;
    }
    class _$ThirdPartyServicesModule extends ThirdPartyServicesModule {
      @override
      DialogService get dialogService => DialogService();
    }
    

    so how can i use final ilanService = getIt(); instead of IlanService ilanService = IlanService(); Bcoz i have to set state in it :( (edited)

    opened by yakupbaser 17
  • No register type error

    No register type error

    I get this error

    No type XUseCase is registered inside GetIt.
     Did you forget to pass an instance name? 
    (Did you accidentally do  GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;
    did you forget to register it?)
    

    get it dont find the XUsCase but is already registered

    sl.registerLazySingleton<XUseCase >(() => XUseCase (sl()));

    opened by oscarshaitan 16
  • GetIt not being able to correctly find registered Type

    GetIt not being able to correctly find registered Type

    Hey all!

    Sorry if this issue is in the wrong format, I didn't find anything mentionind any guidelines on how to write one.

    My app has this issue where I can't get my instance after registering. Through some deep debugging, I've found this method "_findFirstFactoryByNameAndTypeOrNull" inside get_it_impl.dart that compares the given T to a scope's factoriesByName, and this comparison by Map index wasn't working properly.

    In other words; when I run the line:

    final AuthenticationService authService = GetIt.I.get<AuthenticationService>(instanceName: "authentication");
    

    After a while, the package goes through its factories in its scope.

    while (instanceFactory == null && scopeLevel >= 0) {
          final factoryByTypes = _scopes[scopeLevel].factoriesByName[instanceName];
          if (type == null) {
            instanceFactory = factoryByTypes != null
                ? factoryByTypes[T] as _ServiceFactory<T, dynamic, dynamic>?
                : null;
          } else {
            /// in most cases we can rely on the generic type T because it is passed
            /// in by callers. In case of dependent types this does not work as these types
            /// are dynamic
            instanceFactory = factoryByTypes != null
                ? factoryByTypes[type] as _ServiceFactory<T, dynamic, dynamic>?
                : null;
          }
          scopeLevel--;
        }
    

    But when I compare on debug: Captura de Tela 2021-08-17 às 14 03 53

    Am I doing something wrong?

    waiting for customer response 
    opened by AlvBarros 15
  • Allow to register services later in depend on list

    Allow to register services later in depend on list

    I am writing some modularity packages which allows developers to customize each classes by replacing services in DI. The current implementation check depend on list when register services function is called.

    I think it is more reasonable to construct dependency by calling some function like done and DFS the tree for async loading

    opened by Goxiaoy 15
  • [Feature request] Factory classes with manual lifecycle

    [Feature request] Factory classes with manual lifecycle

    It would be helpful to have factory registrations with an extended lifecycle as multiple calls to factory registered class will result as a single instance up to the desired class or when called with a unique ID bound to each factory class. It's like singletons with parameter support. This can be useful in inter bloc communication where Bloc B can add events to Bloc A and injecting or accessing Bloc A inside Bloc B results as the same instance of Bloc A and not a new one. Once Bloc A is closed, the factory class can be reset like lazy singletons or scope.

    I tried using Blocs as lazySingletons and resetting there lifecycle in onClose() method but had to switch to static instance pattern because singletons can't have factoryParams

      static BlocA? _instance;
      
      static BlocA getInstance({
        dynamic? param1,
        dynamic? param2,
      }) {
        if (_instance != null) {
          return _instance!;
        } else {
          return _instance = getIt<BlocA>(
            param1: param1,
            param2: param2,
          );
        }
      }
    
    @override
      Future<void> close() {
        _instance = null;
        return super.close();
      }
    
    opened by vishalrao8 13
  • Ability to know registered object's _ServiceFactoryType type

    Ability to know registered object's _ServiceFactoryType type

    Hey, I'd like to know whether registered object is singleton or not. Use case: I have a wrapper widget around Cubit/Bloc which retrieves correct instance of bloc from getIt, but I have an issue when I'm trying to close/dispose the bloc, there are two cases

    1. Bloc is registered as factory, meaning it okay to close it after its widget disposes
    2. Bloc is Singleton/lazy and I don't want to close it after its widget disposes, but I can't tell if bloc is singleton or not without passing specific parameter to cubit wrapper widget

    Possible solution would be to expose _ServiceFactoryType and call getIt.type() or getIt.typeOf<T>()

    opened by Tkko 0
  • Correct way of disposing registered resources.

    Correct way of disposing registered resources.

    We are using get_it here to totally handle our dependencies instances, and we are using clean architecture as suggested by reso coder tutorial, so we have several layers (viewModel -> usecase -> repository -> data_source), let me show some snippets.

    File structure:

    -lib
    --feature
    ----data
    ------remote_data_source.dart
    ------concrete_repository.dart
    ----domain
    ------abstract_repository.dart
    ------usecase.dart
    ----presentation
    ------my_screen.dart
    ------my_view_model.dart
    

    we have get_it registration file, like this:

      getIt.registerLazySingleton(
        () => MyViewModel(getIt()),
      );
      getIt.registerLazySingleton(
        () => Usecase(getIt()),
      );
      getIt.registerLazySingleton<AbstractRepository>(
        () => ConcreteRepository(getIt()),
      );
      getIt.registerLazySingleton(
        () => RemoteDataSource(getIt()),
      );
    
      //this is the last one
      getIt.registerLazySingleton(
        () => CustomHttpClient(),
      );
    

    And what we are doing is: on the screen, we call final viewModel = getIt<MyViewModel>(), and all the instances are retrieved by a cascading call, lets see:

    • Our ViewModel needs a UseCase on it's constructor,
    • UseCase needs a Repository
    • Repository needs a DataSource
    • DataSource needs an ApiClient.

    And all of these are being resolved by get_it, so when we call: final viewModel = getIt<MyViewModel>(). get_it is creating instances of MyViewModel, Usecase, ConcreteRepository, RemoteDataSource and CustomHttpClient, right?

    This is really fantastic, because we don't have to worry about objects instantiations and it works well.

    My questions

    1 - If I call resetLazySingleton<MyViewModel>() on dispose method of my screen, will get_it cascading reset all the other dependencies?

    The real question is: What is the correct way to dispose these objects when we don't need them anymore?

    opened by luizpaulofranz 0
  • isReady swallows errors from async factories

    isReady swallows errors from async factories

    When an instance is registered with registerSingletonAsync<T> and later checked if it is ready with isReady<T>(), then errors occurring inside the async factory function are swallowed/lost.

    A workaround is to use getAsync<T>() instead where errors are correctly propagated.

    opened by kuhnroyal 0
  • popScopeUntil should allow baseScope with inclusive: false

    popScopeUntil should allow baseScope with inclusive: false

    Thank you for adding the inclusive flag on popScopeUntil. I feel the assert needs to be updated with the new flag though. https://github.com/fluttercommunity/get_it/blob/master/lib/get_it_impl.dart#L795

    This should be valid but fails due to the current assert. Since it's are popping everything except the baseScope.

      await GetIt.I.popScopesTill('baseScope', inclusive: false);
    

    Current:

    assert(scopeName != _baseScopeName, "You can't pop the base scope");
    

    Suggested

    assert(inclusive && scopeName != _baseScopeName, "You can't pop the base scope");
    
    opened by ccadieux 0
Owner
Flutter Community
A central place for all community made Flutter packages. To get started, see the README of the 'community' repository.
Flutter Community
MVC pattern for flutter. Works as state management, dependency injection and service locator.

MVC pattern for flutter. Works as state management, dependency injection and service locator. Model View Controller Here's a diagram describing the fl

xamantra 115 Dec 12, 2022
Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Flutter plugin that leverages Storage Access Framework (SAF) API to get access and perform the operations on files and folders.

Vehement 8 Nov 26, 2022
Home-Service-App - Home Service App Built With Flutter

Home-Service-App Home Service App Sample Images

Justin Roy 2 Sep 4, 2022
Our application, MyArmyPal serves to be an all in one service for our service men.

Our application, MyArmyPal serves to be an all in one service for our service men. It seeks to provide convenience and useful features just one tap away. Its main features include an IPPT Calculator, reservist checklist, customized IPPT training plan according to the user's current fitness level and a canteen order pick up service in all army camps. We are also implementing an anytime Eliss system using computer vision for users to check on their push up form easily.

Poh Wei Pin 3 Jun 17, 2022
A Wi-Fi Direct Plugin for Flutter

flutter_p2p A Wi-Fi Direct Plugin for Flutter. This plugin is in alpha and only supports android at the moment. Getting Started Required permissions P

mintware 77 Dec 22, 2022
Morphing Coffee 0 Jan 27, 2022
Excess Food Locator helps food providers connect with food distributing NGOs.

Excess Food Locator Excess Food Locator helps people having excess food connect with other resources and distributors. This application is based on a

Pranav Kale 6 Nov 6, 2022
System info plus - A Flutter plugin to get device Random Access Memory (RAM) size

system_info_plus A Flutter plugin to get device Random Access Memory (RAM) size.

Sebghatullah Yusuf 2 Aug 21, 2022
🎯 Automatically organize your dart imports. Maintainer: @gleich

___ _____ ______ ________ ________ ________ _________ |\ \|\ _ \ _ \|\ __ \|\ __ \|\ __ \|\___ ___\ \ \ \ \ \\\__\ \ \ \ \|

Flutter Community 138 Dec 12, 2022
Create a Flutter User Profile Page UI where you can access and edit your user's information within your Flutter app.

Flutter Tutorial - User Profile Page UI 1/2 Create a Flutter User Profile Page UI where you can access and edit your user's information within your Fl

Johannes Milke 46 Dec 6, 2022
Create a Flutter User Profile Page UI where you can access and edit your user's information within your Flutter app.

Flutter Tutorial - User Profile Page UI #2 Create a Flutter User Profile Page UI where you can access and edit your user's information within your Flu

Johannes Milke 45 Dec 15, 2022
Responsive Scaffold - On mobile it shows a list and pushes to details and on tablet it shows the List and the selected item. Maintainer: @rodydavis

responsive_scaffold View the online demo here! On mobile it shows a list and pushes to details and on tablet it shows the List and the selected item.

Flutter Community 346 Dec 2, 2022
Cross-platform flutter plugin for reading and writing NFC tags. Not maintained anymore - not looking for new maintainer, fork instead.

nfc_in_flutter NFC in Flutter is a plugin for reading and writing NFC tags in Flutter. It works on both Android and iOS with a simple stream interface

Andi Semler 113 Sep 28, 2022
State Persistence - Persist state across app launches. By default this library store state as a local JSON file called `data.json` in the applications data directory. Maintainer: @slightfoot

State Persistence Persist state across app launches. By default this library store state as a local JSON file called data.json in the applications dat

Flutter Community 70 Sep 28, 2022
Official Sonr Blockchain Node implementation with Frontend Clients to access Wallet.

Sonr Blockchain Sonr-Chain is a blockchain built using Cosmos SDK and Tendermint and created with Starport. Get started starport chain serve serve com

Sonr 625 Dec 29, 2022
Generate secure passwords, check for exposed passwords, get visual feedback for password strength or get form validation with a minimum password strength required.

password_strength_checker Generate secure passwords, check for exposed passwords, get visual feedback for password strength or get form validation wit

Dario Varriale 6 Aug 8, 2023
Firebase dart common interface and implementation for Browser, VM, node and flutter

firebase.dart Firebase dart common interface and implementation for Browser, VM, node and flutter Firebase Initialization Usage in browser import 'pac

Tekartik 6 Nov 28, 2021
Weather app using Bloc architecture pattern & generic HTTP client with interface implementation and much more for more detail read Readme

weather Weather application for current weather, hourly forecast for 48 hours, Daily forecast for 7 days and national weather alerts. How to Run Insta

Jibran Ahmed SiddiQui 9 Oct 29, 2022
Deepak Sharma 149 Dec 10, 2022