Flutter依赖注入与服务定位插件bilocator的使用
Flutter依赖注入与服务定位插件bilocator的使用
bilocator
是一个 Flutter 混合定位器,它管理全局注册表中的模型(类似于 GetIt)和小部件树中的模型(类似于 Provider、InheritedWidget)。bilocator
被 mvvm+
状态管理包所使用,因此经过了实战测试。
Bilocator 目标
- 在全局注册表中定位单个服务。
- 在小部件树中定位继承的模型。
- 将单个服务和继承模型的生命周期绑定到小部件。
- 支持懒加载。
- 支持模型同时在注册表和小部件树中可定位。
- 可单独使用或与其他状态管理包(如 RxDart、Provider、GetIt 等)一起使用。
- 具有可扩展性和高性能,适用于独立开发者和生产应用。
单个服务
单个服务是指那些需要从小部件树的任何地方定位的单个实例。
要将单个服务添加到注册表中,可以给 Bilocator
小部件提供一个构建器,并将其添加到小部件树中:
Bilocator<MyService>(
builder: () => MyService(),
child: MyWidget(),
);
如何定位单个服务
可以通过类型从任何地方定位单个服务实例:
final myService = Bilocator.get<MyService>();
如果需要多个相同类型的单个服务实例,可以指定一个唯一的名称:
Bilocator<MyService>(
builder: () => MyService(),
name: 'some unique name',
child: MyWidget(),
);
然后通过类型和名称获取服务:
final myService = Bilocator.get<MyService>(name: 'some unique name');
当需要在一个小部件中管理多个服务时,可以使用 Bilocators
:
Bilocators(
delegates: [
BilocatorDelegate<MyService>(builder: () => MyService()),
BilocatorDelegate<MyOtherService>(builder: () => MyOtherService()),
],
child: MyWidget(),
);
对于少数需要直接管理注册和注销服务的情况,可以使用静态的 register
和 unregister
函数:
Bilocator.register<MyService>(builder: () => MyService());
继承模型
继承模型位于小部件树中(类似于 Provider、InheritedWidget)。与单个服务不同,你可以根据需要添加任意数量的相同类型的继承模型。
默认情况下,模型存储在注册表中(location: Location.registry
)。要将模型添加到小部件树中,将 location
设置为 Location.tree
:
Bilocator<MyModel>(
builder: () => MyModel(),
location: Location.tree,
child: MyWidget(),
);
Bilocator
小部件在从小部件树中移除时会注销其服务和模型。如果这些服务和模型是 ChangeNotifiers
,Bilocator
小部件可以选择调用 ChangeNotifiers
的 dispose
方法。
定位继承模型
Bilocator
实现了观察者模式作为混入,可以添加到你的模型和小部件中:
class MyModel with Observer {
int counter;
}
使用 Observer
的模型和小部件可以 listenTo
继承模型和单个服务。要监听单个服务:
final text = listenTo<MyWidgetViewModel>(listener: myListener).text;
要监听小部件树上的继承模型,添加 context
参数:
final text = listenTo<MyWidgetViewModel>(context: context, listener: myListener).text;
为了方便起见,Observer
还添加了一个 get
函数,不需要前缀 Bilocator
类名。使用 Observer
的模型和小部件可以获取单个服务:
final text = get<MyModel>().text;
并获取继承模型:
final text = get<MyModel>(context: context).text;
使用 .of
.of
函数(如 Theme.of、Provider.of)被认为会在应用中引入不必要的依赖项(从而导致不必要的构建)。因此,建议使用 listenTo
。但是,如果你正在从使用 of
的其他库迁移(或只是喜欢使用 of
),Bilocator
在其 BuildContext
扩展中包含了 of
:
final text = context.of<MyModel>().text;
或者,你可以使用 BuildContext
扩展来获取模型而不添加依赖项:
final text = context.get<MyModel>().text;
注册继承模型作为单个服务
要使小部件树上的继承模型对其他分支的小部件可见,可以将继承模型注册为单个服务:
register<MyModel>(context);
注册后,模型将从任何地方可用。当不再需要在注册表中时,简单地注销它:
unregister<MyModel>(context);
示例
以下是一个使用 bilocator
的完整示例。该示例中有三个注册的服务:
ColorNotifier
每隔 N 秒更改一次颜色并调用notifyListeners
。FortyTwoService
持有一个等于 42 的数字。RandomService
生成一个随机数。
第一个服务使用 Bilocator
添加到小部件树中。其余服务使用 Bilocators
添加。
import 'dart:async';
import 'dart:math';
import 'package:bilocator/bilocator.dart';
import 'package:flutter/material.dart';
void main() => runApp(myApp());
Widget myApp() => MaterialApp(
home: Bilocators(
delegates: [
BilocatorDelegate<RandomService>(builder: () => RandomService()),
BilocatorDelegate<ColorNotifier>(builder: () => ColorNotifier()),
],
child: Bilocator(
builder: () => Counter(),
location: Location.tree,
child: const Page(),
),
),
);
class Page extends StatefulWidget {
const Page({super.key});
@override
State<Page> createState() => _PageState();
}
class _PageState extends State<Page> with Observer {
@override
void initState() {
super.initState();
get<ColorNotifier>().addListener(() => setState(() {}));
}
@override
void dispose() {
get<ColorNotifier>().removeListener(() => setState(() {}));
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
context.of<Counter>().count.toString(),
style: TextStyle(
fontSize: 64,
color: listenTo<ColorNotifier>(listener: () => setState(() {})).color.value,
),
),
OutlinedButton(
onPressed: () => context.of<Counter>().count = get<RandomService>().number,
child: const Text('Set Random'),
),
OutlinedButton(
onPressed: () => context.of<Counter>().count = 0,
child: const Text('Clear'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => context.of<Counter>().count++,
child: const Icon(Icons.add),
),
);
}
}
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
set count(int value) {
_count = value;
notifyListeners();
}
}
class ColorNotifier extends ChangeNotifier {
int _counter = 0;
late final color = ValueNotifier<Color>(Colors.black)..addListener(notifyListeners);
ColorNotifier() {
_timer = Timer.periodic(const Duration(seconds: 5), (_) {
color.value = [Colors.orange, Colors.purple, Colors.cyan][++_counter % 3];
});
}
late Timer _timer;
@override
void dispose() {
_timer.cancel();
super.dispose();
}
}
class RandomService {
int get number => Random().nextInt(100);
}
那就是全部!
如果有任何关于 bilocator
的问题或建议,请随时联系我。
更多关于Flutter依赖注入与服务定位插件bilocator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter依赖注入与服务定位插件bilocator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用bilocator
进行依赖注入和服务定位的详细代码示例。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加bilocator
的依赖:
dependencies:
flutter:
sdk: flutter
bilocator: ^4.0.0 # 请确保使用最新版本
然后运行flutter pub get
来安装依赖。
2. 配置Bilocator
在你的项目根目录下创建一个新的文件,比如dependency_injection.dart
,用于配置Bilocator。
import 'package:bilocator/bilocator.dart';
// 假设我们有一个简单的服务类
class MyService {
void performAction() {
print("Performing action in MyService");
}
}
// 配置Bilocator
final getIt = GetIt.instance;
void setupLocator() {
// 注册服务
getIt.registerSingleton<MyService>(MyService());
}
3. 初始化Bilocator
在你的应用入口文件(通常是main.dart
)中,初始化Bilocator。
import 'package:flutter/material.dart';
import 'dependency_injection.dart';
void main() {
// 初始化Bilocator
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
4. 使用依赖注入
现在,你可以在任何需要的地方通过getIt
来获取你的服务实例。
import 'package:flutter/material.dart';
import 'dependency_injection.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Bilocator Example'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
// 获取MyService实例并调用方法
final myService = getIt<MyService>();
myService.performAction();
},
child: Text('Perform Action'),
),
),
);
}
}
完整代码结构
pubspec.yaml
:添加依赖dependency_injection.dart
:配置Bilocatormain.dart
:应用入口,初始化Bilocatorhome_screen.dart
(可选,如果分离文件):包含HomeScreen
类
注意事项
- 单例模式:在上面的例子中,
MyService
是通过registerSingleton
方法注册的,这意味着在整个应用中MyService
的实例是唯一的。 - 懒加载:
bilocator
(或get_it
)支持懒加载,即只有在第一次获取实例时才会创建对象。 - 清理资源:如果你的服务持有资源(如数据库连接),你可能需要在应用关闭时清理这些资源。可以通过监听应用生命周期事件来实现。
通过这种方式,你可以轻松地在Flutter应用中使用依赖注入和服务定位,从而提高代码的可测试性和模块化程度。