Singleton<T> class abstract

Container of singleton instance.

Lazy Singleton

Define Lazy Singleton

class MyLazyService {
  /// Factory method that reuse same instance automatically
  factory MyLazyService() => Singleton.lazy(() => MyLazyService._());

  /// Private constructor
  MyLazyService._() {}

  /// do something
  void doSomething() {}
}

Use Lazy Singleton

MyLazyService().doSomething() // Use the singleton instance

Eager Singleton

Define Eager Singleton

class MyEagerService {
  /// Factory method that reuse same instance automatically
  factory MyEagerService() => Singleton.get<MyEagerService>();

  final MyApi api;

  /// Constructor create and register new instance
  MyEagerService.initialize(this.api) {
    // Register current instance
    Singleton.register(this);
  }

  /// do something
  void doSomething() {}
}

Initialize eagerly

void main() {
  final appSettings = getAppSettings();
  final httpClient = createHttpClient(appSetting);
  final api = createMyApi(httpClient);

  MyEagerService.initialize(api) // Create and register the the singleton
                .doSomething();  // Use the instance
}

Use Eager Singleton

MyEagerService().doSomething(); // Use the singleton instance

Future Singleton

Define the type

Given some other dependants declarations

class AppSettings {
  static Future<AppSettings> loadAppSettings() {
    // load app settings from somewhere asynchronously
  }
}

class HttpClient {
  final AppSettings appSettings;

  HttpClient(this.appSettings);
}
class MyFutureService {
  /// Factory method that reuse same instance automatically
  factory MyFutureService() => Singleton.get<MyFutureService>();

  static Future<MyFutureService> createInstance() async {
    final appSettings = await Singleton<AppSettings>().ensuredInstance();

    final httpClient = HttpClient(appSettings);

    return MyFutureService._(httpClient);
  }

  final HttpClient httpClient;

  MyFutureService._(this.httpClient);

  /// Some method
  void doSomething() {}
}

Register future as singleton

Singleton.register understands future, it register value of future as singleton rather than register future itself

void main() {
  // Register AppSettings settings as a future singleton
  Singleton.register(AppSettings.loadAppSettings());

  // Create and register the the MyService as singleton
  Singleton.register(MyFutureService.createInstance());

  runApp();
}

Use future singleton

For sure you still can use this approach to consume future singleton.

MyFutureService().doSomething();

It is likely to be okay if when async resource although load asynchronously but will be available fast, such as SharedPreferences. But you might encounter StateError says "singleton is being used before being resolved".

Availability checkpoint

(await Singleton<MyService>().ensuredInstance()).doSomething();

This is a more reliable way, but it removes almost all the benefits to have a sync singleton.

So run following code before usage, such as in main after register all singleton types


void main() async {
  // Register AppSettings settings as a future singleton
  Singleton.register(AppSettings.loadAppSettings());

  // Create and register the the MyService as singleton
  Singleton.register(MyFutureService.createInstance());

  await Singleton.ensureInstanceFor([AppSettings, MyFutureService]); //  Ensure all singletons are properly initialized

  runApp();
}

Then use future singleton in normal way

MyService().doSomething();

Constructors

Singleton([String? name = null])
Get the singleton wrapper for type [T}
factory
Singleton.register(FutureOr<T> value, {String? name = null})
Register a singleton T with given value
factory
Singleton.registerLazy(SingletonFactory<T> factory, {String? name = null})
Register or fetch a lazy type singleton wrapper for T
factory

Properties

hashCode int
The hash code for this object.
no setterinherited
instance → T
Get value of singleton
no setter
key SingletonKey
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited

Methods

deregister([String? name = null]) → void
Deregister singleton from registry
ensuredInstance() Future<T>
A FutureOr use to ensure the value is created.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited

Static Methods

debugPrintAll(dynamic type) → void
Prints singletons of given type if type are omitted, all singletons are printed.
ensureInstanceFor(dynamic type) Future
Ensure type singleton instances exists
get<T>({String? name = null}) → T
Retrieve an pre-registered singleton For T via register.
lazy<T>(SingletonFactory<T> factory, {String? name = null}) → T
Register or fetch a lazy singleton for T
resetAllForTest() → void
Debug API to clear all registered singleton to avoid pollution across tests caused by singleton
withName<T>([String? name = null]) SingletonKey
Create SingletonKey for given type T and name