简介
官方提供的一个简单的状态管理库。
关键点:
- 提取状态:状态变量和UI分离
- 访问状态:将UI和状态建立联系
- 使用状态:读取状态变量
前置知识
1、InheritedWidget
关键点:
- Element持有Widget对象
- Element也是一个BuildContext对象
- Element里面持有所有的
InheritedElement
所以:通过BuildContext对象可以拿到所需的Widget对象,然后访问里面的数据。
父节点存放数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class InheritedShareWidget extends InheritedWidget { final int data; InheritedShareWidget({this.data, Widget child}) : super(child: child);
static InheritedShareWidget of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<InheritedShareWidget>();
}
@override bool updateShouldNotify(covariant InheritedShareWidget oldWidget) { return oldWidget.data != this.data; } }
|
子节点获取数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class TestShareChildWidget extends StatefulWidget { const TestShareChildWidget({Key key}) : super(key: key); @override _TestShareChildWidgetState createState() => _TestShareChildWidgetState(); }
class _TestShareChildWidgetState extends State<TestShareChildWidget> { @override void didChangeDependencies() { super.didChangeDependencies(); print("enter didChangeDependencies"); }
@override Widget build(BuildContext context) { print("enter child build"); final data = InheritedShareWidget.of(context).data.toString(); return Text(data); } }
|
父子节点嵌套:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class _TestInheritedWidgetState extends State<TestInheritedWidget> { int count = 0;
@override Widget build(BuildContext context) { return Center( child: InheritedShareWidget( data: count, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TestShareChildWidget(), RaisedButton( child: Text('add'), onPressed: () { setState(() { ++count; }); }) ],),),);}}
|
2、InheritedProvider
关键点:
- 通过
InheritedProvider
及其子类(如:ChangeNotifierProvider)来包裹其他Widget(child),其实是将child放入了_InheritedProviderScope
_InheritedProviderScope
是一个InheritedWidget
所以,InheritedProvider
及其子类将会持有child对象,及其数据。
Provider的基本使用
1 2 3 4 5 6 7 8 9
| class Person with ChangeNotifier { String name = "ChangeNotifierProvider";
void changName({required String newName}) { name = newName; notifyListeners(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MainApp extends StatelessWidget { const MainApp({super.key});
@override Widget build(BuildContext context) { return ChangeNotifierProvider<Person>( create: (ctx) => Person(), child: const MaterialApp( home: ChangeNotifierProviderDemo(), ), ); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class ChangeNotifierProviderDemo extends StatelessWidget { const ChangeNotifierProviderDemo({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("ChangeNotifierProvider")), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Consumer<Person>( builder: (ctx, person, child) => Text(person.name), ), Consumer<Person>( builder: (ctx, person, child) { return ElevatedButton( onPressed: () => person.changName(newName: "ChangeNotifierProvider更新了"), child: const Text("点击更新"), );},),],),),);} }
|
Provider的类结构
3.1 InheritedProvider的子类只是具体功能的实现,基础逻辑封装在InheritedProvider中
3.2 InheritedProvider将职责转嫁给_InheritedProviderScope而_InheritedProviderScope是一个InheritedWidget
如何实现监听
1、数据实现了ChangeNotifier,变更后调用notifyListeners(),触发回调。
2、ChangeNotifierProvider继承自ListenableProvider,ListenableProvider构建时开启监听:
1 2 3 4 5 6 7
| static VoidCallback _startListening( InheritedContext e, Listenable? value, ) { value?.addListener(e.markNeedsNotifyDependents); return () => value?.removeListener(e.markNeedsNotifyDependents); }
|
class InheritedContext extends BuildContext{
void markNeedsNotifyDependents();
}
3、markNeedsNotifyDependents是InheritedContext
中的方法,其实现类是_InheritedProviderScopeElement
1 2 3 4 5 6 7 8 9
| @override void markNeedsNotifyDependents() { if (!_isNotifyDependentsEnabled) { return; }
markNeedsBuild(); _shouldNotifyDependents = true; }
|
4、markNeedsBuild是Element的方法:标记需要重新构建
1 2 3 4 5 6 7 8
| void markNeedsBuild() { ... if (dirty) { return; } _dirty = true; owner!.scheduleBuildFor(this); }
|
局部更新
Provider的Selector
提供了缓存Widget的功能,当Widget没有变化时,将直接返回缓存,否则重新build。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class _Selector0State<T> extends SingleChildState<Selector0<T>> { T? value; Widget? cache; Widget? oldWidget;
@override Widget buildWithChild(BuildContext context, Widget? child) { final selected = widget.selector(context);
final shouldInvalidateCache = oldWidget != widget || (widget._shouldRebuild != null && widget._shouldRebuild!(value as T, selected)) || (widget._shouldRebuild == null && !const DeepCollectionEquality().equals(value, selected)); if (shouldInvalidateCache) { value = selected; oldWidget = widget; cache = widget.builder( context, selected, child, ); } return cache!; }
@override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<T>('value', value)); } }
|
参考
https://juejin.cn/post/7067356022272163847#heading-16