Provider的使用
Provider是flutter官方提供的用来进行状态管理的一个框架,简单的可以理解为,当一个数据对象变化时,我们希望UI中能同步的更新,它能自动的监听变化,避免了手动调用的过程。
首先导入依赖
dependencies:
provider: ^6.0.3
它的原理其实还是观察者模式,在最顶层的widget上包裹一个Provider,创建出我们需要监听的数据,在子widget中就可以拿到变化的数据。
1、创建一个被观察的对象,这个类中包含了我们所需要监听的数据
class Counter with ChangeNotifier{
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
2、在最顶层的widget,用一个Provider包裹起来
child: ChangeNotifierProvider<Counter>(create: (_)=>Counter(),child: MyApp(),)
// 上面是用范型的方式指定数据对象,也可以用下面的这种方式
child: ChangeNotifierProvider.value(
value: Counter(),
child: MyApp()
),
注意,这里不要使用Provider,因为它不会更新UI,要使用ChangeNotifierProvider或者是
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Counter()),
],
child: const MyApp(),
),
如果有多个对象就用上面这种。
3、在要使用的地方将其取出来
floatingActionButton: FloatingActionButton(
key: const Key('increment_floatingActionButton'),
/// Calls `context.read` instead of `context.watch` so that it does not rebuild
/// when [Counter] changes.
onPressed: () => context.read<Counter>().increment(),
tooltip: 'Increment',
child: const Icon(Icons.add),
),
上面一个是context.read, 这样widget不会被重建,在需要改变的地方就要用context.watch了
Widget build(BuildContext context) {
return Text(
/// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
'${context.watch<Counter>().count}',
key: const Key('counterState'),
style: Theme.of(context).textTheme.headline4);
}
也可以用下面的这种方式
@override
Widget build(BuildContext context) {
var counter = Provider.of<Counter>(context);
return Text(
/// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
'${counter.count}',
key: const Key('counterState'),
style: Theme.of(context).textTheme.headline4);
}
不过上面的这种方式不推荐使用,因为刷新的时候其他的子widget也会跟着一起刷新,比较影响性能。
或者用Consumer的方式
Widget build(BuildContext context) {
return Consumer<Counter>(builder: (_,counter,child){
return Text(counter.count.toString());
});
}
综上来看,还是context.watch和Consumer的方式要简单一些。
Selector
上面我们说了Consumer,Selector其实和Consumer差不多,只是Consumer处理的是一个对象,但是Selector处理的更精细一些,它可以处理一个对象中的某些成员,过滤掉一些不关心的数据,还是以上面的例子,我们将Counter改成
class Counter with ChangeNotifier{
int _count = 0;
String _name = "";
int get count => _count;
String get name => _name;
void increment() {
_count++;
notifyListeners();
}
void setName(){
_name += "a";
notifyListeners();
}
}
增加了一个name字段,下面通过一个Selector来监听它的变化
class NameWidget extends StatelessWidget {
const NameWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Selector<Counter, String>(
builder: (_, name, child){
return Text(name);
},
selector: (_, counter) => counter.name,);
}
}
Selector也是一个范型类,需要传入对象和成员的类型Counter, String,然后在它的selector函数中选择需要处理的成员,在builder中构建一个Widget返回。
Timer使用
timer不需要再导入就来就可以使用了,一般我们就用它来做两件事情
1、每隔一定的时间去做一件事,周期性执行
2、一段时间后执行,只执行一次。
下面看一下它的用法
1、5s后执行
Timer timer1 = Timer(const Duration(seconds: 5), (){
print("dosomething");
});
2、每隔1s执行一次
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
_setNowTime();
});
需要注意的是Timer在创建完成后就开始计时了,不需要再调用start()之类的方法, 需要取消时调用timer.cancel()取消, 第二个参数是一个回调函数。