知识FlutterFlutter-Provider
KahviaProvider是第三方状态管理的库。就我目前的水平来看,它貌似能代替 StatefulWidget 和 InheritedWidget 。
安装(带^表示可以自动更新)
1 2
| dependencies: provider: ^6.0.3
|
使用
-
创建数据模型(自定义类),继承 ChangeNotifier ,暴露想要共享的数据, 以及创建可选的修改数据的方法。
-
创建观察者,或者说数据模型的提供者——Provider。
- 通过Provider()提供的数据通常是不可变的。
- 通过ChangeNotifierProvider()提供的数据可以改变,并可以通过调用notifyListeners()来更新使用到共享数据的组件。
- 和 InheritedWidget 类似,包裹需要使用共享数据的子孙组件。包裹一次,子孙组件都可以作为监听者(listener)使用数据。
- 为 create 属性提供构造器,需要传入上下文context
- child 子组件,也就是包裹的子孙组件
-
作为 Listener 使用共享数据。因为时常需要响应数据的变化,所以叫监听者。
-
context.watch < Type >( ).atributeName,通过上下文的注入方法(由provider自动注入,也就是附加方法)来获取数据。
-
Provider.Of< Type >(context).atributeName, 通过Provider的静态方法来获取数据。
-
查看源码发现,第一种方法就是封装后的第二种方法
-
T watch<T>() {
return Provider.of<T>(this);
}
<!--code1-->
观察者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Home extends StatelessWidget { const Home({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (BuildContext context)=>LikeData(), child: Scaffold( appBar: AppBar( title: const Text('Provider'), leading: const Icon(Icons.menu), actions: const[Icon(Icons.settings)], ), body: MyPage(), ), ); } }
|
监听者(使用到共享数据的那一部分)
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 33 34 35 36 37
| Widget titleSection = Builder( builder: (BuildContext context)=>Container( padding: const EdgeInsets.all(32), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Hello,this is Alice!", style: TextStyle( fontWeight: FontWeight.bold, ), ), Text( "Good evening!", style: TextStyle( color: Colors.grey[500], ), ) ], ), ), IconButton( icon: Icon(context.watch<LikeData>().liking?Icons.star:Icons.star_border), color: Colors.red, onPressed: context.watch<LikeData>().changeLikeState, ), Text( "${Provider.of<LikeData>(context).number}", ) ], ), ) );
|
ps
代码实现的功能和之前测试的“有状态组件”一样,都是实现收藏功能和它的收藏数变化。
不同的地方是,使用provider后,没有使用状态组件进行状态管理。但是很显然,这种共享数据的模式在多重嵌套组件下,可以更好的实现状态管理,而不用通过构造函数传递所需数据,也不需要通过手动调用 setState()进行组件的重新渲染。