小菜前几天学习了一下新的状态管理框架 Provider,Provier 支持多种类型的状态管理方式,小菜继续学习其余几种;
ListenableProvider 方式
1. 数据绑定
ListenableProvider({Key key, @required ValueBuilder<T> builder, Disposer<T> dispose, Widget child })
通过构造器绑定数据并进行监听,当从 Widget Tree 中删除时 dispose 要销毁;注意:构造器 builder 不可为空;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ListenableProvider<User>( builder: (_) => User('Flutter', 0), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}
复制代码
ListenableProvider.value({Key key, @required T listenable, Widget child })
通过 .value 方式对数据进行监听 listenable;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ListenableProvider<User>.value( listenable: User('Flutter', 0), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}
复制代码
2. 获取数据
小菜在上一篇博客中未曾提及,基本所有的获取数据方式基本相同且均支持两种方式;
Provider.of(context) 方式
class ProviderText extends StatelessWidget { @override Widget build(BuildContext context) { final user = Provider.of<User>(context); return Text('${user.getName}'); }}
复制代码
Consumer Widget 构造器方式
class ProviderText extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer<User>(builder: (context, user, _) { return Text(user.getName); }); }}
复制代码
ValueListenableProvider 方式
使用 ValueListenableProvider 方式时要注意,需要绑定的数据要继承自 ValueNotifier<T>,并实现其构造方法,通过对 value 的操作进行更新;小菜新建一个 person 实体类进行操作;
// 基本数据类型class StringBean extends ValueNotifier<String> { StringBean(String value) : super(value);}
// 自定义实体类class Person extends ValueNotifier<User> { Person(User value) : super(value); String get getPersonName => value.name;
void setPersonName(String name) { value.name = name; notifyListeners(); }}
复制代码
1. 绑定数据
ValueListenableProvider({Key key, @required ValueBuilder<ValueNotifier<T>> builder, UpdateShouldNotify<T> updateShouldNotify, Widget child })
通过构造器绑定数据并进行监听,且构造器 builder 不可为空;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ValueListenableProvider<User>( builder: (_) => Person(User('person', 101)), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}
复制代码
ValueListenableProvider.value({Key key, @required ValueListenable<T> valueListenable, UpdateShouldNotify<T> updateShouldNotify, Widget child })
通过 .value 方式对数据进行绑定监听;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ValueListenableProvider<User>.value( valueListenable: Person(User('person', 101)), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}
复制代码
2. 获取数据
获取数据的方式与上述基本一致;
class ProviderText extends StatelessWidget { @override Widget build(BuildContext context) { final number = Provider.of<String>(context); final person = Provider.of<User>(context); return Center( child: Column(children: <Widget>[ Text('${number.toString()}==${person.getName}'), Consumer<User>(builder: (context, user, _) { return Text(user.getName); }) ])); }}
复制代码
StreamProvider 方式
1. Stream 简介
Stream 存在于 Dart:async 库中,主要用于处理异步操作;在 ListView 展示网络接口数据时曾用到过;小菜对 Stream 的理解还不够深入,基本理解为一个处理器,通过 StreamController<T>()..sink.add() 输入需要处理的数据,通过 StreamController<T>()..stream 输出处理后的数据;整个过程都需要通过 StreamController 来控制;具体的单 stream 和多 stream 方式小菜稍后研究;
2. 绑定数据
StreamProvider({Key key, @required ValueBuilder<StreamController<T>> builder, T initialData, ..., Widget child })
通过构建器创建 StreamController 然后绑定数据,注意需要在 initialData 中初始化绑定数据;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return StreamProvider<Teacher>( builder: (_) => StreamController<Teacher>(), initialData: Teacher('Teacher', 101), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}
class Teacher { var tname; var tage;
Teacher(this.tname, this.tage);}
Expanded(child: TextField( onChanged: (changed) { teacher.tname = changed; teacher.tage = 150; StreamController<Teacher>().sink.add(teacher); }, controller: _phonecontroller, decoration: InputDecoration( hintText: '请输入用户名', suffixIcon: IconButton( icon: Icon(Icons.clear, color: Colors.black45), onPressed: () { _phonecontroller.clear(); }))))
复制代码
StreamProvider.value({Key key, @required Stream<T> stream, T initialData, ..., Widget child })
通过 .value 方式对 StreamController 的 stream 进行数据绑定,同样需要在 initialData 中初始化数据;
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return StreamProvider<Teacher>.value( stream: StreamController<Teacher>().stream, initialData: Teacher('Teacher', 101), child: MaterialApp( title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue), home: MyHomePage(title: 'Peovider Demo'))); }}
复制代码
3. 获取数据
class ProviderText extends StatelessWidget { @override Widget build(BuildContext context) { final teacher = Provider.of<Teacher>(context); return Center( child: Column(children: <Widget>[ Text('${teacher.tname}'), Consumer<Teacher>(builder: (context, teacher, _) { return Text('${teacher.tname}==${teacher.tage}'); }) ])); }}
复制代码
小结
为方便理解,结合上一节的 ChangeNotifierProvider,发现与 ListenableProvider 和 ValueListenableProvider 的使用基本相同;
class ChangeNotifierProvider<T extends ChangeNotifier> extends ListenableProvider<T> implements SingleChildCloneableWidget {}class ChangeNotifier implements Listenable {} class ValueListenableProvider<T> extends AdaptiveBuilderWidget<ValueListenable<T>, ValueNotifier<T>> implements SingleChildCloneableWidget {}class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> {}
复制代码
分析源码:ChangeNotifierProvider 继承自 ListenableProvider 且对应的 ChangeNotifier 继承自 listenable;算是 ListenableProvider 的子类;ValueNotifier 继承自 ChangeNotifier 也与 ChangeNotifierProvider 相似;
使用 ChangeNotifierProvider 和 ValueListenableProvider 绑定实体类时需要注意分别继承对应的 ChangeNotifier 和 ValueNotifier;
class User with ChangeNotifier {}
class Person extends ValueNotifier<User> {}
复制代码
无论使用那种 .value 方式,均建议在 dispose 中进行 listener 的关闭;
@overridevoid dispose() { stream.dispose(); super.dispose();}
复制代码
小菜将 Provier 中提及的五种方式均尝试了一下,对于同一类的实体类也进行测试,如有错误请多多指导!
来源:阿策小和尚
评论