bilocator 0.6.0 bilocator: ^0.6.0 copied to clipboard
A locator that manages models in a global registry (like GetIt) and in the widget tree (like Provider, InheritedWidget).
bilocator #
A Flutter hybrid locator that manages models in a global registry (like GetIt) and in the widget tree (like Provider, InheritedWidget).
Bilocator is used my by the state management packages, so is battle tested.
Bilocator goals:
- Locate single services in a global registry.
- Locate inherited models in the widget tree.
- Bind the lifecycle of both single services and inherited models to widgets.
- Support lazy loading.
- Support models being simultaneously locatable in the registry and on the widget tree.
- Work alone or with other state management packages (RxDart, Provider, GetIt, ...).
- Be scalable and performant, so suitable for both indy and production apps.
Bilocator can be used as a standalone locator or integrated into state management libraries. mvvm+ uses Bilocator.
Single Services #
Single services are those single instances that need to located from anywhere in the widget tree.
To add a single service to the registry, give a builder to a Bilocator widget and add it to the widget tree:
Bilocator<MyService>(
builder: () => MyService(),
child: MyWidget(),
);
Inherited Models #
Inherited models are located on the widget tree (similar to Provider, InheritedWidget). Unlike single services, you can add as many inherited models of the same type as you need.
By default, models are stored in the registry (location: Location.registry
). To add models to the widget tree, set location
to Location.tree
:
Bilocator<MyModel>(
builder: () => MyModel(),
location: Location.tree,
child: MyWidget(),
);
Bilocator widgets unregister their services and models when they are removed from the widget tree. If their services and models are ChangeNotifiers, the Bilocator widgets optionally call the ChangeNotifiers' dispose
method.
How to Locate Single Services #
The single service instance can located from anywhere by type:
final myService = Bilocator.get<MyService>();
If more than one instance of a service of the same type is needed, you can specify a unique name:
Bilocator<MyService>(
builder: () => MyService(),
name: 'some unique name',
child: MyWidget(),
);
And then get the service by type and name:
final myService = Bilocator.get<MyService>(name: 'some unique name');
When you want to manage multiple services with a single widget, use Bilocators:
Bilocators(
delegates: [
BilocatorDelegate<MyService>(builder: () => MyService()),
BilocatorDelegate<MyOtherService>(builder: () => MyOtherService()),
],
child: MyWidget(),
);
For rare use cases where you need to directly manage registering and unregistering services (instead of letting Bilocator and Bilocators manage your services), you can use the static register
and unregister
functions:
Bilocator.register<MyService>(builder: () => MyService())
Locating Inherited Models #
Bilocator implements the observer pattern as a mixin that can my added to your models and widgets.
class MyModel with Observer {
int counter;
}
Models and widgets that use Observer can listenTo
inherited models and single services. To listen to single services:
final text = listenTo<MyWidgetViewModel>(listener: myListener).text;
To listen to inherited models on the widget tree, add the context
parameter:
final text = listenTo<MyWidgetViewModel>(context: context, listener: myListener).text;
For convenience, Observer also adds a get
function that doesn't required the preceding Bilocator class name. Models and widgets that use Observer can get single services:
final text = get<MyModel>().text;
And get inherited models:
final text = get<MyModel>(context: context).text;
.of #
The of
function (Theme.of, Provider.of) is known to introduce unnecessary dependencies in apps (and consequently unnecessary builds). So, using listenTo
is recommended. However, if you are migrating from another library that uses of
(or simply like using of
), Bilocator includes of
in its BuildContext extension:
final text = context.of<MyModel>().text;
Or, you get use the BuildContext extension to get models without adding a dependency:
final text = context.get<MyModel>().text;
Registering an Inherited Model as a Single Service #
To make an inherited model on the widget tree visible to widgets on other branches, register the inherited model as a single service:
register<MyModel>(context);
After registering, the model will be available from anywhere. When no longer needed in the registry, simply unregister it:
unregister<MyModel>(context);
Some Trivia #
In the non-technical world, religious zealots and mystics that claim to have the power of locating in two places at once are referred to as bilocators.
Example #
(The source code for this example is under the Pub.dev "Example" tab and in the GitHub example/lib/main.dart
file.)
There are three registered services:
- ColorNotifier changes its color every N seconds and then calls
notifyListeners
. - FortyTwoService holds a number that is equal to 42.
- RandomService generates a random number.
The first service was added to the widget tree with Bilocator
. The remaining services were added with Bilocators
.
That's It! #
If you have questions or suggestions on anything Bilocator, please do not hesitate to contact me.