bilocator 0.6.1 copy "bilocator: ^0.6.1" to clipboard
bilocator: ^0.6.1 copied to clipboard

A locator that manages models in a global registry (like GetIt) and in the widget tree (like Provider, InheritedWidget).

bilocator #

bilocator logo

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 MVVM+ 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:

  1. ColorNotifier changes its color every N seconds and then calls notifyListeners.
  2. FortyTwoService holds a number that is equal to 42.
  3. RandomService generates a random number.

The first service was added to the widget tree with Bilocator. The remaining services were added with Bilocators.

example

That's It! #

If you have questions or suggestions on anything Bilocator, please do not hesitate to contact me.

5
likes
140
pub points
54%
popularity

Publisher

verified publisherrichardcoutts.com

A locator that manages models in a global registry (like GetIt) and in the widget tree (like Provider, InheritedWidget).

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

equatable, flutter

More

Packages that depend on bilocator