能够进行依赖注入和状态管理,使用widget建立,适用于widget。async
它是故意设计成使用widget来进行依赖注入和状态管理的,而不是纯使用dart类,像是stream这些。由于widget简单且健壮可伸缩。ide
使用weidget来进行状态管理能够保证。函数
除了暴露一个值的可访问性,provider还包括这个值的建立,监听,销毁。测试
为了暴露一个新建立的对象,可使用provider的默认构造函数。不要使用.value
命名构造函数类建立一个值对象,否则可能会形成其余不指望影响。fetch
create
中建立一个对象。Provider( create:(_)=>new MyModel(), child:... )
Provider.value
命名构造函数建立一个对象。ChangeNotifierProvider.value( value:new MyModel(), child:... )
若是建立了一个对象,它使用了为了可能变动的变量作参数,那么考虑使用ProxyProvider:ui
int count; ProxyProvider0( update:L(_,__)=> new MyModel(count), child:... )
若是有个对象实例,你想把其暴露在其余地方使用,那么你应该使用Provider的.value
命名构造函数。this
不这么作可能会形成在该对象还在使用时被dispose
。设计
ChangeNotifierProvider.value
来提供一个已经存在的ChangeNotifier
。MyChangeNotifier varibale; ChangeNotifierProvider.value( value:variable, child:... )
CahangeNotifier
。MyChangeNotifier variable; ChangeNotifierProvider( create:(_)=>variable, child:... )
获取一个值最简单的方法是使用静态方法Provider.of<T>(BuildContext context)
。code
这个方法会从当前的context在widget树中向根widget方向查找符合类型T的最近的值。(若是没有找到就throw)。对象
除了Provider.of
方法咱们也可使用Consumer
和Selector
两个widget。
这对于高效的组织代码以及难以获取BuildContext
的状况比较有帮助。
当在一个较大的应用中注入较多的数据时,Provider会飞快地嵌套多层。
Provider<Something>( create:(_)=>Something(), child: Provider<SomethingElse>( create:(_)=>SomethingElse(), child:Provider<AnotherThing>( create:(_)=>AnotherTing(), child:someWidget, ) ) )
能够这样写
MultiProvider( Providers:[ Provider<Somthing>(create:(_)=>Something()), Provider<SomthingElse>(create:(_)=>SomethingElse()), Provider<AnotherThing>(create:(_)=>AnotherTthing()), ], child:someWidget )
上面代码的结果是严格的同样的。MultiProvider
仅仅是改变了代码的形式。
从版本3.0.0开始增长了一个新的Provider:ProxyProvider。
ProxyProvider自己是一个Provider,它把其余多个provider的数据结合成一个新的对象,而且把这个结果发送一个一个Provider。
被结合的的这些provider中的任何一个数据更新了,这个新的对象都会更新。
下面这个例子使用了ProxyProvider,他把其余provider中的counter作了个中转。
Widget build(BuildContext context){ return MultiProvider( providers:[ ChangeNotifierProvider(create:(_)=>Counter()), ProxyProvider<Counter,Translations>( create:(_,counter,__)=>Translations(clunter.value), ), child:Foo() ] ) } class Translations{ const Translations(this._value); final init _value; String get title=>'You clicked: $_value times'; }
ProxyProvider有不少种变体,例如:
ProxyProvider
vs ProxyProvider2
vs ProxyProvider3
...类名后的数字是指ProxyProvider
依赖其余Provider的数量。
ProxyProvider
vs ChangeNotifierProxyProvider
vs ListenableProxyProvider,...他们的工做方式是相似的,相对于发送结果给一个Provider,一个ChangeNotifierProxyProvider
会发送给一个ChangeNotifierProxyProvider
。这个错误是由于你想监听一个在其生命周期中不会被再次调用的provider。
这说明你不会再使用其余的生命周期(didChangeDependencies/build),或者你不在意数据更新。
不要这么作
initState(){ super.initState(); print(Provider.of<Foo>(context).value); }
你能够这么作
Value value; didChangeDependencies(){ super.didChangeDependencies(); final value = Provider.of<Foo>(context).value; if(value != this.value){ this.value = value; print(value); } }
每当值发生了变化,都会被打印。
也能够这么作
initState(){ super.initState(); print(Provider.of<Foo>(context,listen:false).value); }
这样只会打印value一次,再也不更新。
ChangeNotifier
,当我更新数据时发生了错误,发生了什么?这个常常发生在widget树正在构建时,你对ChangeNotifier进行了更改操做。
一个典型的情景是,发起了一个http请求,而后该future被保存在了notifer中。
initState(){ super.initState(); Provider.of<Foo>(context).fetchSomething(); }
这样是禁止的,由于更改必须是当即的。
这意味着有些widget可能在变更以前build,然而其余的在变更以后build。这可能会形成你的ui发生冲突,因此是禁止的。
相比,你能够在整个widget树都同步以后(渲染前/选而后?)进行变更。
class Mymodel width ChangeNotifier{ MyModel(){ _fetchSomething(); } Future<void> _fetchSomething()async {} }
这个适用于没有额外参数的状况。
initState(){ super.initState(); Future.microtash(()=>{ Provider.of<Foo>(context).fetchSomething(someValue); }) }
这个多少是不太理想的,可是容许传入参数进行变动。
不是。
你可使用任何对象来呈现状态。例如其余可用的方式是Provider.value()结合一个StatefulWidget使用。
这里有个计数的例子,使用了这个方法:
class Example extends StatefulWidget{ const Example({Key key, this.child}):super(key key); final Widget child; @override ExampleState createState()=> ExampleState(); } class ExampleState extends State<Example>{ int _count; void increment(){ setState((){ _count++; }) } @override Widget build(BuildContext context){ return Provider.value( value:_count, child:Provider.value( value:this, child:widget.child ) ) } }
能够如此读取数据:
return Text(Provider.of<int>(context).toString());
如此更改数据:
return FloatingActionButton( onPress:Provider.of<Examp0leState>(context).increment, child:Icon(Icons.plus_one), );
此外,你也能够建立本身的provider。
固然,provider暴露了全部的小的组件,这些制做了一个简陋的provider。
包括:
相较于Provider.of,你可使用Consumer/Selector。
他们可选的child参数只容许重建widget中很是小的具体部分。
Foo( child:Consumer<A>( builder:(_,a,child){ return Bar(a:a,child:child); } child: Baz(), ), )
这个例子中只有Bar会在A更新时被重建,Foo和Baz非必要下不会更新。
更深一步,使用selector来忽略widget树中一些没有影响的更新也是可能的。
Selector<List,int>( selector:(_,list)=>list.length, builder:(_,length,__){ return Text('$length'); } );
这个代码片断中,只有list的length变化时,才会被重构。即便一个item发生了变化也不会更新。
不能。
你可使用多个Provider共享一样的类型,一个widget只能获取到他们中的一个:最近的那个。
否则,你必须给与不一样的provider不一样的数据类型。
相较:
Provider<String>( create:(_)=>'england', child:Provider<String>( create:(_)=>'London', child:... ) )
推荐:
Provider<Country>( create:(_)=>'england', child:Provider<City>( create:(_)=>'London', child:... ) )
provider包提供了一些不一样类新的'provider'应对不一样类型的对象。
以下:
名字 | 说明 |
---|---|
Provider | provider的最基本形式,能够添加和暴露任何形式的值 |
ListenableProvider | 使用Listenable对象的特殊provider,ListenableProvider会监听对象,而且在监听器在任什么时候候调用时要求widget重构。 |
ChangeNotifierProvider | ChangeNotifier规格的ListenableProvider,他会在必要时自动调用ChangeNotifier.dispose. |
ValueListenableProvider | 监听一个ValueListenable而且只暴露ValueListenable.value。 |
StreamProvider | 监听Stream而且暴露最新的emitted的值。 |
FutureProvider | 添加一个Future,而且在future完成时更新附从。 |