在Dart和Flutter工程中,为一个组件提供对象/服务的默认方式是通过InheritedWidget。
还有Provider、Singleton、IoC等方式。
1.1 InheritedWidget
如果希望一个部件或其模型能够访问服务,则组件必须是继承的组件的子组件。然后这会导致不必要的嵌套。而且依赖性强,持续性维护差。
///创建数据类 DataWidget,然后在页面中用数据类DataWidget包含页面child部分
///1、创建 DataWidget
class DataWidget extends InheritedWidget {
DataWidget({
@required this.data,
Widget child
}) :super(child: child);
final int data;
static DataWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<DataWidget>();
}
@override
bool updateShouldNotify(DataWidget old) {
return old.data != data;
}
}
///2、创建 InheritedWidgetTestRoute.dart 文件
class InheritedWidgetTestRoute extends StatefulWidget {
@override
_InheritedWidgetTestRouteState createState() => new _InheritedWidgetTestRouteState();
}
class _InheritedWidgetTestRouteState extends State<InheritedWidgetTestRoute> {
int count = 0;
@override
Widget build(BuildContext context) {
return Center(
child: DataWidget( // 重点:使用DataWidget包裹
data: count,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Text(DataWidget.of(context)
.data.toString())
),
RaisedButton(
child: Text("Increment"),
//每点击一次,将count自增,然后更新页面渲染,DataWidget的data将被更新
onPressed: () => setState(() => ++count),
)
],
),
),
);
}
}
复制代码
1.2 Provider
为组件提供对象/服务,还有一种方式是使用Provider,使用比较繁琐。
///创建数据类 `CountNotifier`,然后在页面中用数据类 `CountNotifier`包裹child部分。
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 创建 Widget 持有 CountNotifier 数据
return ChangeNotifierProvider.value(
value: CountNotifier(),
child: MaterialApp(
title: 'Privoder Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ProvidePage(title: 'Provider 测试页面'),
),
);
}
}
class ProvidePage extends StatelessWidget {
final String title;
ProvidePage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
// 获取 CountNotifier 数据 (最简单的方式)
final counter = Provider.of<CountNotifier>(context);
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text( '按下按钮,使数字增加:', ),
Text(
'${counter.count}',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counter.increment();
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
/// 核心:继承自ChangeNotifier
/// 可以单独放在一个类文件里
class CountNotifier with ChangeNotifier {
int _count = 0;
int get count => _count;
increment() {
_count++;
// 核心方法,通知刷新UI,调用build方法
notifyListeners();
}
}
复制代码
1.3 Singleton、IoC
我们也可以通过其他的方式在App中的任意位置获取到要访问的对象,但是:
-
如果使用Singleton,则无法轻松地将实现切换到另一个(例如用于单元测试的模拟版本)
-
用于依赖项注入的IoC容器提供了类似的功能,但代价是启动时间慢且可读性差,因为不知道神奇注入的对象来自何处。 由于大多数IoC库都依赖反射,因此它们不能与Flutter一起使用。
1.4 GetIt
在App迭代发展中,随着代码工程的增长,在某些时候需要将App的部分逻辑放在与Widget分离的类中。使Widget不具有直接依赖关系可以使代码更好地组织并更易于测试和维护。但是现在需要一种从 UI 代码访问这些对象的方法。
作者escamoteur 借鉴.net中的Service Locator Splat概念,在Dart中开发而成。
Service Locators 的概念,它是一种将接口(抽象基类)与具体实现解耦的方法,同时允许通过接口从您的 App 中的任何地方访问具体实现。
故GetIt应运而生,从1.0到现在的7.x
二、介绍
2.1 定义
[GetIt] 官方介绍
This is a simple Service Locator for Dart and Flutter projects with some additional goodies highly inspired by Splat. It can be used instead of
InheritedWidgetorProviderto access objects e.g. from your UI.Typical usage:
- Accessing service objects like REST API clients or databases so that they easily can be mocked.
- Accessing View/AppModels/Managers/BLoCs from Flutter Views
V7.0 has some breaking changes Check please check the release notes to see what's new.
译文:
GetIt是一个用于 Dart 和 Flutter 项目的简单服务定位器,其中包含一些受到 Splat 启发的附加功能。 它可以用来代替 InheritedWidget 或 Provider 比如从你的用户界面来访问对象。
典型用法(使用场景):
- 访问 REST API 客户端或数据库等服务对象,以便轻松模拟它们
- 从 Flutter 视图访问 View/AppModels/Managers/BLoCs
简而言之
GetIt是一个简单的直接服务定位器,允许将接口与具体实现分离,并从应用程序的任何地方访问具体实现。
一句话总结
GetIt是一个工具箱。
2.2 特点
- 调用极快 (复杂度O(1))
- 易学/易用
- 不会像提供程序或 Redux 那样使用特殊的小部件来使您的 UI 树混乱以访问您的数据。
Redux 的设计思想很简单,就两句话。
(1)Web 应用是一个状态机,视图与状态是一一对应的。
(2)所有的状态,保存在一个对象里面。
三、使用
3.1 引入
在某包下的pubspec.yaml引入框架
dependencies:
flutter:
sdk: flutter
domain_common:
path: ../domain_common
res_common:
path: ../res_common
provider: ^5.0.0
get_it: ^7.1.3
复制代码
