Flutter-Provider

Provider是第三方状态管理的库。就我目前的水平来看,它貌似能代替 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}",//获取共享数据的第二种方法
// "520"
)
],
),
)
);

ps

代码实现的功能和之前测试的“有状态组件”一样,都是实现收藏功能和它的收藏数变化。

不同的地方是,使用provider后,没有使用状态组件进行状态管理。但是很显然,这种共享数据的模式在多重嵌套组件下,可以更好的实现状态管理,而不用通过构造函数传递所需数据,也不需要通过手动调用 setState()进行组件的重新渲染。