flutter_it library

A convenience package that re-exports the entire flutter_it ecosystem.

This package provides a single import for all flutter_it packages:

  • get_it: Service locator and dependency injection
  • watch_it: Reactive state management built on get_it
  • command_it: Command pattern with automatic loading/error states
  • listen_it: ValueListenable operators and reactive collections

Instead of importing each package separately:

import 'package:get_it/get_it.dart';
import 'package:watch_it/watch_it.dart';
import 'package:command_it/command_it.dart';
import 'package:listen_it/listen_it.dart';

You can now just import:

import 'package:flutter_it/flutter_it.dart';

Learn more at https://flutter-it.dev

Classes

Command<TParam, TResult>
Command capsules a given handler function that can then be run by its run method. The result of this method is then published through its ValueListenable interface Additionally it offers other ValueListenables for it's current execution state, if the command can be run and for all possibly thrown exceptions during command execution.
CommandAsync<TParam, TResult>
CommandBuilder<TParam, TResult>
CommandError<TParam>
CommandError wraps an occurring error together with the argument that was passed when the command was called. This sort of objects are emitted on the .errors ValueListenable of the Command
CommandResult<TParam, TResult>
Combined execution state of a Command represented using four of its fields. A CommandResult will be issued for any state change of any of its fields During normal command execution you will get this items by listening at the command's .results ValueListenable.
CommandSync<TParam, TResult>
CustomChangeNotifier
CustomValueNotifier<T>
Sometimes you want a ValueNotifier where you can control when its listeners are notified. With the CustomValueNotifier you can do this: If you pass CustomNotifierMode.always for the mode parameter, notifierListeners will be called everytime you assign a value to the value property independent of if the value is different from the previous one. If you pass CustomNotifierMode.manual for the mode parameter, notifierListeners will not be called when you assign a value to the value property. You have to call it manually to notify the Listeners. Aditionally it has a listenerCount property that tells you how many listeners are currently listening to the notifier.
Disposable
If objects that are registered inside GetIt implements Disposable the onDispose method will be called whenever that Object is unregistered, reset or its enclosing Scope is popped
ErrorFilerConstant
ErrorFilter
Instead of the current parameter catchAlways commands can get an optional parameter errorFilter of type ErrorFilter which can be used to customize the error handling. Additionally there will be a Global error Filter that is used if no local error filter is present.
ErrorFilterExcemption<T>
GetIt
Very simple and easy to use service locator You register your object creation factory or an instance of an object with registerFactory, registerSingleton or registerLazySingleton And retrieve the desired object using get or call your locator as function as its a callable class Additionally GetIt offers asynchronous creation functions as well as functions to synchronize the async initialization of multiple Singletons
GlobalErrorFilter
Error filter that routes errors only to the global handler. Use this when you want all errors to go to the global handler, regardless of whether there are local listeners.
GlobalIfNoLocalErrorFilter
Error filter that routes errors to global handler if no local handler is present. This is the default error filter for all commands.
InitDependency
Data structure used to identify a dependency by type and instanceName
ListenableSubscription
Object that is returned by listen that allows you to stop the calling of the handler that you passed to it.
ListNotifier<T>
A List that behaves like ValueNotifier if its data changes.
LocalAndGlobalErrorFilter
Error filter that routes errors to both local and global handlers.
LocalErrorFilter
Error filter that routes errors only to local handlers (.errors or .results listeners).
MapNotifier<K, V>
A Map that behaves like ValueNotifier if its data changes.
MockCommand<TParam, TResult>
MockCommand allows you to easily mock an Command for your Unit and UI tests Mocking a command with mockito https://pub.flutter-io.cn/packages/mockito has its limitations.
ObjectRegistration<T extends Object>
PredicatesErrorFilter
Takes a list of predicate functions and returns the first non null ErrorReaction or ErrorReaction.defaulErrorFilter if no predicate matches. The predicates are called in the order of the list. which means if you want to match against a type hierarchy you have to put the more specific type first. You can define your own predicates or use the errorFilter function like this
ProgressHandle
Provides bidirectional communication for commands with progress tracking, status messages, and cooperative cancellation.
SetNotifier<T>
A Set that behaves like ValueNotifier if its data changes.
ShadowChangeHandlers
If an object implements the ShadowChangeHandler if will get notified if an Object with the same registration type and name is registered on a higher scope which will shadow it. It also will get notified if the shadowing object is removed from GetIt
TableErrorFilter
This filter allows to pass a table of error types and the corresponding ErrorReactions. Attention, the table can only compare the runtime type of the error on equality, not the type hierarchy. Normally you couldn't match against the Excpeption type, because the runtime type of an exception is always _Exception which is a private type. As Exception is such a basic error type this funcion has a workaround for this case. I recommend to use the PredicatesErrorFilter instead unless you have a very specific use case that requires to compare for type equality.
UndoableCommand<TParam, TResult, TUndoState>
UndoStack<E>
WatchingStatefulWidget
WatchingWidget
WatchItSubTreeTraceControl
An inherited widget that controls tracing behavior for WatchingWidgets in its subtree.
WillSignalReady
If your singleton that you register wants to use the manually signalling of its ready state, it can implement this interface class instead of using the signalsReady parameter of the registration functions (you don't really have to implement much ;-) )

Enums

CustomNotifierMode
ErrorReaction
ObjectRegistrationType
You will see a rather esoteric looking test (const Object() is! T) at several places. It tests if T is a real type and not Object or dynamic. For each registered factory/singleton an ObjectRegistration<T> is created it holds either the instance of a Singleton or/and the creation functions for creating an instance when get is called
WatchItEvent
Enum representing different types of events in watch_it

Extensions

FunctionaListener on ValueListenable<T>
extension functions on ValueListenable that allows you to work with them almost as if it was a synchronous stream. Each extension function returns a new ValueNotifier that updates its value when the value of this changes You can chain these functions to build complex processing pipelines from a simple ValueListenable In the examples we use listen to react on value changes. Instead of applying listen you could also pass the end of the function chain to a ValueListenableBuilder
FunctionaListener2 on Listenable
ToWidgeCommandResult on CommandResult<TParam, TResult>
ValueListenablePipe on ValueListenable<T>
Extension to pipe ValueListenable changes to a Command.

Properties

di GetIt
WatchIt exports the default instance of get_it as a global variable which lets you access it from anywhere in your app. To access any get_it registered object you only have to type di<MyType>() instead of GetIt.I<MyType>(). if you don't want to use a different instance of get_it you can pass it to the functions of this library as an optional parameter
final
enableSubTreeTracing bool
Global switch to enable/disable subtree tracing
getter/setter pair
sl GetIt
for people taking offense that the name di is not correct because GetIt is a service locator and not a dependency injection container, we provide an alias for it.
final
watchItLogFunction WatchItLogFunction?
Global logging function that can be overridden by users Default implementation prints to console
getter/setter pair

Functions

allReady({void onReady(BuildContext context)?, void onError(BuildContext context, Object? error)?, Duration? timeout, bool callHandlerOnlyOnce = false}) bool
returns true if all registered async or dependent objects are ready and call onReady and onError handlers when the all-ready state is reached. You can force a timeout Exception if allReady hasn't returned true within timeout. It will trigger a rebuild if this state changes If no onError is passed in it will throw an exception if an error occurs while waiting for the all-ready state. callHandlerOnlyOnce determines if the onReady and onError handlers should be called only once or on every rebuild after the all-ready state has been reached.
allReadyHandler(void onReady(BuildContext context)?, {void onError(BuildContext context, Object? error)?, Duration? timeout, bool callHandlerOnlyOnce = false}) → void
registers a handler that is called when the all-ready state is reached it does not trigger a rebuild like allReady does. You can force a timeout Exception if allReady has completed within timeout which will call onError if no onError is passed in it will throw an exception if an error occurs while waiting for the all-ready state. callHandlerOnlyOnce determines if the onReady and onError handlers should be called only once or on every rebuild after the all-ready state has been reached.
callAfterEveryBuild(void callback(BuildContext context, void cancel())) → void
Executes a callback after every frame has been rendered. This is useful when you need to perform operations after each rebuild that require the widget tree to be fully built and laid out, such as:
callOnce(void init(BuildContext context), {void dispose()?}) → void
If you want to execute a function only on the first built (even in in a StatelessWidget), you can use the callOnce function anywhere in your build function. It has an optional dispose handler which will be called when the widget is disposed.
callOnceAfterThisBuild(void callback(BuildContext context)) → void
Executes a callback once after the current build has been rendered. This is useful when you need to perform operations that require the widget tree to be fully built and laid out, such as:
createOnce<T extends Object>(T factoryFunc(), {void dispose(T)?}) → T
createOnce creates an object with the factory function factoryFunc at the time of the first build and disposes it when the widget is disposed if the object implements the Disposable interface. on every rebuild the same object is returned dispose allows you to pass a custom dispose function to dispose of the object. if provided it will override the default dispose behavior.
createOnceAsync<T>(Future<T> factoryFunc(), {required T initialValue, void dispose(T)?}) AsyncSnapshot<T>
createOnceAsync creates an object with the async factory function factoryFunc at the time of the first build and disposes it when the widget is disposed if the object implements the Disposable interface. initialValue is the value that will be returned until the factory function completes. When the factoryFunc completes the value will be updated with the new value and the widget will be rebuilt. dispose allows you to pass a custom dispose function to dispose of the object. if provided it will override the default dispose behavior.
enableTracing({bool logRebuilds = true, bool logHandlers = true, bool logHelperFunctions = true}) → void
enable tracing for the current build function has to be called before any other watch_it functions in the same build function If both logRebuilds and logHandlers are true then both will be logged if you want to enable tracing for the complete subtree you can wrap the widget that you want to trace including its child widgets with WatchItSubTreeTraceControl
errorFilter<TError>(Object error, ErrorReaction reaction) ErrorReaction?
isReady<T extends Object>({void onReady(BuildContext context)?, void onError(BuildContext context, Object? error)?, Duration? timeout, String? instanceName}) bool
returns true if the registered async or dependent object defined by T and instanceName is ready and calls onReady onError handlers when the ready state is reached. You can force a timeout Exception if isReady hasn't returned true within timeout. It will trigger a rebuild if this state changes. if no onError is passed in it will throw an exception if an error occurs
onDispose(void dispose()) → void
To dispose anything when the widget is disposed you can use call onDispose anywhere in your build function.
pushScope({void init(GetIt getIt)?, void dispose()?, bool isFinal = false}) → void
Pushes a new GetIt-Scope. After pushing, it executes init where you can register objects that should only exist as long as this scope exists. Can be called inside the build method of a StatelessWidget. It ensures that it's only called once in the lifetime of a widget. isFinal allows only objects in init to be registered so that other components cannot accidentally register to this scope. When the widget is destroyed the scope also gets destroyed after dispose is executed. If you use this function and you have registered your objects with an async disposal function, that function won't be awaited. I would recommend doing pushing and popping from your business layer but sometimes this might come in handy.
rebuildOnScopeChanges() bool?
Will trigger a rebuild of the Widget if any new GetIt-Scope is pushed or popped. This function will return true if the change was a push otherwise false. If no change has happened then the return value will be null.
registerChangeNotifierHandler<T extends ChangeNotifier>({required void handler(BuildContext context, T newValue, void cancel()), T? target, bool executeImmediately = false, String? instanceName, GetIt? getIt}) → void
registerChangeNotifierHandler registers a handler function for a ChangeNotifier exactly once on the first build and unregisters it when the widget is destroyed. If you set executeImmediately to true the handler will be called immediately with the current value of the ChangeNotifier and not on the first change notification. All handler functions get passed in a cancel function that allows to kill the registration from inside the handler. If you want to register a handler to a ChangeNotifier that is not registered in get_it you can pass it as target. instanceName is the optional name of the instance if you registered it with a name in get_it.
registerFutureHandler<T extends Object, R>({Future<R> select(T)?, T? target, required void handler(BuildContext context, AsyncSnapshot<R?> newValue, void cancel()), R? initialValue, String? instanceName, bool callHandlerOnlyOnce = false, bool allowFutureChange = false, GetIt? getIt}) → void
registerFutureHandler registers a handler function for a Future exactly once on the first build and unregisters it when the widget is destroyed. This handler will only be called once when the Future completes. select allows you to register the handler to a member of the of the Object stored in GetIt. If you pass initialValue your passed handler will be executed immediately with that value. All handlers get passed in a cancel function that allows to kill the registration from inside the handler. If the Future has completed handler will be called every time until the handler calls cancel or the widget is destroyed
registerHandler<T extends Object, R>({ValueListenable<R> select(T)?, required void handler(BuildContext context, R newValue, void cancel()), T? target, bool allowObservableChange = false, bool executeImmediately = false, String? instanceName, GetIt? getIt}) → void
registerHandler registers a handler function for a ValueListenable exactly once on the first build and unregister it when the widget is destroyed. select allows you to register the handler to a member of the of the Object stored in GetIt. If you set executeImmediately to true the handler will be called immediately with the current value of the ValueListenable and not on the first change notification. All handler functions get passed in a cancel function that allows to kill the registration from inside the handler. If you want to register a handler to a Listenable that is not registered in get_it you can pass it as target. if you pass null as select, T or target has to be a Listenable or ValueListenable.
registerStreamHandler<T extends Object, R>({Stream<R> select(T)?, required void handler(BuildContext context, AsyncSnapshot<R?> newValue, void cancel()), R? initialValue, bool allowStreamChange = false, T? target, String? instanceName, GetIt? getIt}) → void
registerStreamHandler registers a handler function for a Stream exactly once on the first build and unregisters it when the widget is destroyed. select allows you to register the handler to a member of the of the Object stored in GetIt. If you pass initialValue your passed handler will be executed immediately with that value All handler functions get passed in a cancel function that allows to kill the registration from inside the handler. If you want to register a handler to a Stream that is not registered in get_it you can pass it as target. if you pass null as select, T or target has to be a Stream<R>. instanceName is the optional name of the instance if you registered it with a name in get_it.
throwIf(bool condition, Object error) → void
Two handy functions that help me to express my intention clearer and shorter to check for runtime errors
throwIfNot(bool condition, Object error) → void
watch<T extends Listenable>(T target) → T
The Watch functions:
watchFuture<T extends Object, R>(Future<R> select(T)?, {T? target, required R initialValue, String? instanceName, bool preserveState = true, bool allowFutureChange = false, GetIt? getIt}) AsyncSnapshot<R>
watchFuture observes the Future returned by select and triggers a rebuild as soon as this Future completes. After that it returns an AsyncSnapshot with the received data from the Future When you call watchFuture a second time on the same Future it will return the last received data but not observe the Future a another time. To be able to use watchFuture inside a build function we have to pass initialValue so that it can return something before the Future has completed if select returns a different Future than on the last call, watchFuture will ignore the completion of the previous Future and observe the completion of the new Future. preserveState determines then if the new initial value should be the last value of the previous Future or again initialValue If you want to observe a Future that is not registered in get_it you can pass it as target. if you pass null as select, T or target has to be a Future<R>. instanceName is the optional name of the instance if you registered it with a name in get_it.
watchIt<T extends Listenable>({String? instanceName, GetIt? getIt}) → T
watchIt observes any Listenable registered in get_it and triggers a rebuild whenever it notifies a change. Its basically a shortcut for watch(di<T>()) instanceName is the optional name of the instance if you registered it with a name in get_it. getIt is the optional instance of get_it to use if you don't want to use the default one. 99% of the time you won't need this.
watchPropertyValue<T extends Listenable, R>(R selectProperty(T), {T? target, String? instanceName, GetIt? getIt}) → R
watchPropertyValue allows you to observe a property of a Listenable object and trigger a rebuild whenever the Listenable notifies a change and the value of the property changes and returns the current value of the property. You can achieve a similar result with watchIt<UserManager>().userName but that would trigger a rebuild whenever any property of the UserManager changes. final userName = watchPropertyValue<UserManager, String>((user) => user.userName); could be an example. Or even more expressive and concise: final userName = watchPropertyValue((UserManager user) => user.userName); which lets tha analyzer infer the type of T and R.
watchStream<T extends Object, R>(Stream<R> select(T)?, {T? target, R? initialValue, bool preserveState = true, bool allowStreamChange = false, String? instanceName, GetIt? getIt}) AsyncSnapshot<R>
watchStream subscribes to the Stream returned by select and returns an AsyncSnapshot with the latest received data from the Stream Whenever new data is received it triggers a rebuild. When you call watchStream a second time on the same Stream it will return the last received data but not subscribe another time. To be able to use watchStream inside a build function we have to pass initialValue so that it can return something before it has received the first data if select returns a different Stream than on the last call, watchStream will cancel the previous subscription and subscribe to the new stream. preserveState determines then if the new initial value should be the last value of the previous stream or again initialValue If you want to observe a Stream that is not registered in get_it you can pass it as target. if you pass null as select, T or target has to be a Stream<R>. instanceName is the optional name of the instance if you registered it with a name in get_it.
watchValue<T extends Object, R>(ValueListenable<R> selectProperty(T), {bool allowObservableChange = false, String? instanceName, GetIt? getIt}) → R
watchValue observes a ValueListenable property of an object registered in get_it and triggers a rebuild whenever it notifies a change and returns its current value. It's basically a shortcut for watchIt<T>().value As this is a common scenario it allows us a type safe concise way to do this. final userName = watchValue<UserManager, String>((user) => user.userName); is an example of how to use it. We can use the strength of generics to infer the type of the property and write it even more expressively like this: final userName = watchValue((UserManager user) => user.userName);

Typedefs

DisposingFunc<T> = FutureOr Function(T param)
Signature for disposing function because closures like (x){} have a return type of Null we don't use FutureOr<void>
ErrorFilterFn = ErrorReaction Function(Object error, StackTrace stackTrace)
Function-based error filter for simple inline error handling logic.
ErrorFilterPredicate = ErrorReaction? Function(Object error, StackTrace stackTrace)
ExecuteInsteadHandler<TParam> = RunInsteadHandler<TParam>
Deprecated: Use RunInsteadHandler instead.
FactoryFunc<T> = T Function()
Signature of the factory function used by non async factories
FactoryFuncAsync<T> = Future<T> Function()
Signature of the factory function used by async factories
FactoryFuncParam<T, P1, P2> = T Function(P1 param1, P2 param2)
For Factories that expect up to two parameters if you need only one use void for the one you don't use
FactoryFuncParamAsync<T, P1, P2> = Future<T> Function(P1 param1, P2 param2)
For async Factories that expect up to two parameters if you need only one use void for the one you don't use
RunInsteadHandler<TParam> = void Function(TParam?)
ScopeDisposeFunc = FutureOr Function()
Signature for disposing function on scope level
UndoFn<TUndoState, TResult> = FutureOr<TResult> Function(UndoStack<TUndoState> undoStack, Object? reason)
Type signature of a function that is called when the last command call should be undone.
WatchItLogFunction = void Function({required WatchItEvent eventType, Object? lastValue, Object? observedObject, Object? parentObject, String? sourceLocationOfWatch})
Typedef for the logging function signature

Exceptions / Errors

UndoException
In case that an undo of a command fails, this exception wraps the error to distinguish it from other exceptions.
WaitingTimeOutException