Flutter作用域管理插件dart_scope的使用
Flutter作用域管理插件dart_scope的使用
dart_scope
是一个声明式依赖注入库,它使用 Dart 语法和 Flutter 风格。以下是该插件的一些特性:
- 完全基于 Dart 实现,不依赖于 Flutter。
- 配置与 Dart 语言的语法对齐。
- 配置与 Flutter 小部件的风格对齐。
- 作用域策略与函数的作用域对齐。
- 可以处理异步设置。
目录
快速浏览
让我们通过一些快速示例来探索 dart_scope
的用法。假设我们有以下类:
class Repository {
// ...实现细节
}
class AppNotifier {
AppNotifier({
required this.repository,
});
final Repository repository;
// ...实现细节
void dispose() {}
}
使用 Scope.root(...)
使用 Scope.root(...)
创建顶级作用域并配置:
Future<void> scopeRootExample() async {
final rootScope = await Scope.root([
Final<Repository>(name: 'repository', equal: (scope) => Repository()),
Final<AppNotifier>(name: 'appNotifier', equal: (scope) => AppNotifier(
repository: scope.get<Repository>(name: 'repository'),
)),
]);
// 解析实例
final myRepository = rootScope.get<Repository>(name: 'repository');
final myAppNotifier = rootScope.get<AppNotifier>(name: 'appNotifier');
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
}
使用 name
使用不同的名称创建多个实例:
Future<void> multipleNamesExample() async {
final rootScope = await Scope.root([
Final<Repository>(name: 'repository1', equal: (scope) => Repository()),
Final<Repository>(name: 'repository2', equal: (scope) => Repository()),
Final<Repository>(name: 'repository3', equal: (scope) => Repository()),
]);
final myRepository1 = rootScope.get<Repository>(name: 'repository1');
final myRepository2 = rootScope.get<Repository>(name: 'repository2');
final myRepository3 = rootScope.get<Repository>(name: 'repository3');
print('myRepository1: $myRepository1');
print('myRepository2: $myRepository2');
print('myRepository3: $myRepository3');
}
Scope.root(...)
异步设置
如果需要异步设置(如解析 SharedPreferences
),可以这样做:
Future<Repository> createRepositoryAsync() async {
await Future<void>.delayed(Duration(seconds: 1));
return Repository();
}
Future<void> scopeRootAsyncExample() async {
final rootScope = await Scope.root([
AsyncFinal<Repository>(equal: (scope) async {
return await createRepositoryAsync();
}),
Final<AppNotifier>(equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
)),
]);
final myRepository = rootScope.get<Repository>();
final myAppNotifier = rootScope.get<AppNotifier>();
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
}
使用 scope.push(...)
使用 scope.push(...)
创建新的子作用域。子作用域继承父作用域中的获取器:
class AddTodoNotifier {}
Future<void> scopePushExample() async {
final rootScope = await Scope.root([
Final<Repository>(equal: (scope) => Repository()),
Final<AppNotifier>(equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
)),
]);
// 创建子作用域
final childScope = await rootScope.push([
Final<AddTodoNotifier>(equal: (scope) => AddTodoNotifier()),
]);
// 在子作用域中解析实例
final myRepository = childScope.get<Repository>();
final myAppNotifier = childScope.get<AppNotifier>();
final myAddTodoNotifier = childScope.get<AddTodoNotifier>();
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
print('myAddTodoNotifier: $myAddTodoNotifier');
}
使用 scope.has<T>(...)
使用 scope.has<T>(...)
检查是否已暴露实例:
Future<void> scopeHasExample() async {
final rootScope = await Scope.root([
Final<Repository>(equal: (scope) => Repository()),
Final<AppNotifier>(equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
)),
]);
final childScope = await rootScope.push([
Final<AddTodoNotifier>(equal: (scope) => AddTodoNotifier()),
]);
// 检查父作用域
print(rootScope.has<Repository>()); // true
print(rootScope.has<AppNotifier>()); // true
print(rootScope.has<AddTodoNotifier>()); // false
// 检查子作用域
print(childScope.has<Repository>()); // true
print(childScope.has<AppNotifier>()); // true
print(childScope.has<AddTodoNotifier>()); // true
}
使用 scope.getOrNull<T>(...)
使用 scope.getOrNull<T>(...)
安全地解析实例。此方法在实例未被暴露时返回 null
:
Future<void> scopeGetOrNullExample() async {
final rootScope = await Scope.root([
Final<Repository>(equal: (scope) => Repository()),
Final<AppNotifier>(equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
)),
]);
final childScope = await rootScope.push([
Final<AddTodoNotifier>(equal: (scope) => AddTodoNotifier()),
]);
print(rootScope.getOrNull<Repository>()); // Instance of 'Repository'
print(rootScope.getOrNull<AppNotifier>()); // Instance of 'AppNotifier'
print(rootScope.getOrNull<AddTodoNotifier>()); // null
print(childScope.getOrNull<Repository>()); // Instance of 'Repository'
print(childScope.getOrNull<AppNotifier>()); // Instance of 'AppNotifier'
print(childScope.getOrNull<AddTodoNotifier>()); // Instance of 'AddTodoNotifier'
}
使用 scope.dispose()
作为 scope.push
的相反操作,作用域也可以被销毁/弹出。我们可以注册销毁逻辑,当作用域被销毁时运行:
Future<void> scopeDisposeExample() async {
final rootScope = await Scope.root([
Final<Repository>(equal: (scope) => Repository()),
Final<AppNotifier>(
equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
),
// 注册销毁实例逻辑
dispose: (appNotifier) => appNotifier.dispose(),
),
]);
// 销毁作用域将同时销毁 `appNotifier`
rootScope.dispose();
}
(非)懒惰赋值
实例默认是懒惰赋值的,这意味着它们将在第一次访问时分配。如果我们需要立即分配,只需将 lazy
设置为 false
:
Future<void> nonLazyFinalExample() async {
final rootScope = await Scope.root([
Final<Repository>(
equal: (scope) => Repository(),
lazy: false // 设置为 false
),
Final<AppNotifier>(
equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
),
lazy: false // 设置为 false
),
]);
final myRepository = rootScope.get<Repository>();
final myAppNotifier = rootScope.get<AppNotifier>();
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
}
高级功能
我们已经涵盖了 dart_scope
的基本部分:
- 配置与 Dart 语言的语法对齐。
- 作用域策略与函数的作用域对齐。
- 可以处理异步设置。
接下来,我们将探索高级功能:
- 配置与 Flutter 小部件的风格对齐。
- 配置可组合/可分解。
配置
我们已经使用 Scope.root
和 scope.push
创建了新的作用域:
class Scope {
// Scope.root(...)
static FutureOr<Scope> root(List<Configurable> configure);
// scope.push(...)
FutureOr<Scope> push(List<Configurable> configure);
...
}
创建 Scope
需要配置,称为 Configurable
:
abstract class Configurable {
FutureOr<void> configure(ConfigurableScope scope);
}
Configurable
是一个接口,要求有一个 configure
方法。让我们通过一些示例来了解其工作原理。
内联配置
以前,我们见过这个示例:
Future<void> example() async {
final rootScope = await Scope.root([
Final<Repository>(equal: (scope) => Repository()),
Final<AppNotifier>(
equal: (scope) => AppNotifier(
repository: scope.get<Repository>(),
),
dispose: (appNotifier) => appNotifier.dispose(),
),
]);
final myRepository = rootScope.get<Repository>();
final myAppNotifier = rootScope.get<AppNotifier>();
}
我们可以使用内联 Configurable
达到相同的效果:
Future<void> configurableInlineExample() async {
final rootScope = await Scope.root([
// 内联 `Configurable`
Configurable((scope) {
// 构建依赖图
late final Repository repository = Repository();
late final AppNotifier appNotifier = AppNotifier(
repository: repository,
);
// 在当前作用域中暴露实例
scope.expose<Repository>(expose: () => repository);
scope.expose<AppNotifier>(expose: () => appNotifier);
// 注册销毁逻辑
scope.addDispose(() {
appNotifier.dispose();
});
// 完成
}),
]);
final myRepository = rootScope.get<Repository>();
final myAppNotifier = rootScope.get<AppNotifier>();
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
}
内联 Configurable
使用闭包 (scope) { ... }
来以自定义方式配置当前作用域,步骤包括:
- 使用赋值构建依赖图
late final Repository repository = Repository();
- 使用
scope.expose(...)
暴露实例 - 使用
scope.addDispose(...)
注册销毁逻辑
此闭包仅在作用域创建期间运行一次。它用于以可定制的方式配置作用域。内联 Configurable
仅为了方便使用,如果需要扩展,可以创建实现 Configurable
接口的类。
分解配置
一般来说,高层配置可以拆分为低层 Configurable
,这样更容易重用和组合。这就是 Final
的来源,以及它是如何工作的:
class MyFinal<T> implements Configurable {
MyFinal({
this.name,
required this.equal,
this.dispose,
this.lazy = true,
});
final Object? name;
final T Function(ScopeGet scope) equal;
final void Function(T)? dispose;
final bool lazy;
@override
FutureOr<void> configure(ConfigurableScope scope) {
final T Function() getValue;
if (lazy) {
late final instance = equal(scope);
getValue = () => instance;
} else {
final instance = equal(scope);
getValue = () => instance;
}
scope.expose<T>(name: name, expose: getValue);
if (dispose != null) {
scope.addDispose(() {
final instance = getValue();
dispose!(instance);
});
}
}
}
Configurable
类似于 Flutter 小部件,configure
方法类似于 build
方法。现在我们可以像这样使用 MyFinal
:
Future<void> configurableExample() async {
final rootScope = await Scope.root([
MyFinal<Repository>(
name: 'repository',
equal: (scope) => Repository(),
lazy: false,
),
MyFinal<AppNotifier>(
name: 'appNotifier',
equal: (scope) => AppNotifier(
repository: scope.get<Repository>(name: 'repository'),
),
lazy: false,
dispose: (appNotifier) => appNotifier.dispose(),
),
]);
final myRepository = rootScope.get<Repository>(name: 'repository');
final myAppNotifier = rootScope.get<AppNotifier>(name: 'appNotifier');
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
}
组合配置
高层配置通常与低层配置组合/组合在一起:
class AppConfigurables extends ConfigurableCombine {
const AppConfigurables({
this.repositoryName,
this.appNotifierName,
this.lazy = true,
this.dispose = true,
});
final Object? repositoryName;
final Object? appNotifierName;
final bool lazy;
final bool dispose;
@override
List<Configurable> combine() {
return [
MyFinal<Repository>(
name: repositoryName,
equal: (scope) => Repository(),
lazy: lazy,
),
MyFinal<AppNotifier>(
name: appNotifierName,
equal: (scope) => AppNotifier(
repository: scope.get<Repository>(name: repositoryName),
),
lazy: lazy,
dispose: dispose
? (appNotifier) => appNotifier.dispose()
: null,
),
];
}
}
AppConfigurables
是多个 Configurable
的组合,类似于高层 Flutter 小部件是由低层小部件组成的。然后它可以这样使用:
Future<void> configurableCombineExample() async {
final rootScope = await Scope.root([
AppConfigurables(),
]);
final myRepository = rootScope.get<Repository>();
final myAppNotifier = rootScope.get<AppNotifier>();
print('myRepository: $myRepository');
print('myAppNotifier: $myAppNotifier');
}
更多关于Flutter作用域管理插件dart_scope的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter作用域管理插件dart_scope的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是关于如何在Flutter项目中使用dart_scope
插件进行作用域管理的一个简单代码示例。dart_scope
插件允许你在Dart中创建和管理作用域,这对于状态管理、依赖注入等场景非常有用。
首先,你需要确保你的Flutter项目中已经添加了dart_scope
依赖。你可以在你的pubspec.yaml
文件中添加以下依赖:
dependencies:
flutter:
sdk: flutter
dart_scope: ^最新版本号 # 请替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
接下来,让我们看一个如何使用dart_scope
的简单示例。假设我们有一个简单的Flutter应用,它需要在不同的作用域中管理一些数据。
1. 初始化Scope
首先,我们需要定义一个Scope
并在应用中初始化它。Scope
可以看作是一个容器,用于存储和管理数据。
import 'package:flutter/material.dart';
import 'package:dart_scope/dart_scope.dart';
void main() {
// 创建并初始化一个全局Scope
final myScope = Scope();
myScope.provide(key: 'counter', value: 0);
runApp(MyApp(scope: myScope));
}
2. 创建Flutter应用
接下来,我们创建一个Flutter应用,并在其中使用我们初始化的Scope
。
class MyApp extends StatelessWidget {
final Scope scope;
MyApp({required this.scope});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Scope Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(scope: scope),
);
}
}
3. 使用ScopeProvider和ScopeConsumer
在MyHomePage
中,我们可以使用ScopeProvider
来提供我们的Scope
,并使用ScopeConsumer
来消费作用域中的数据。
import 'package:flutter/material.dart';
import 'package:dart_scope/dart_scope.dart';
class MyHomePage extends StatefulWidget {
final Scope scope;
MyHomePage({required this.scope});
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _incrementCounter() {
final counter = widget.scope.get<int>(key: 'counter') ?? 0;
widget.scope.provide(key: 'counter', value: counter + 1);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Scope Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ScopeConsumer<int>(
scope: widget.scope,
key: 'counter',
builder: (context, counter) {
return Text(
'You have pushed the button this many times:',
style: TextStyle(fontSize: 18),
);
},
child: Text(
'${counter ?? 0}',
style: Theme.of(context).textTheme.headline4,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
在这个示例中,我们定义了一个简单的计数器应用。我们使用ScopeProvider
来提供我们的Scope
,并使用ScopeConsumer
来消费作用域中的counter
值。当按钮被点击时,我们更新作用域中的counter
值,并调用setState
来刷新UI。
请注意,这个示例中的ScopeConsumer
是一个简化的版本,用于演示目的。在实际使用中,dart_scope
插件可能提供了更具体或更灵活的API来消费作用域中的数据。
希望这个示例能帮助你理解如何在Flutter项目中使用dart_scope
插件进行作用域管理。如果你有更具体的需求或问题,请查阅dart_scope
的官方文档以获取更多信息。