1.概念
Flutter Provider是一种状况办理库,它答应经过一个中心组件来传递和同享数据。它运用了InheritedWidget,建立了一个数据传递的上下文树来完结数据同享。
2.长处
Provider的核心理念是将数据放置在顶层同享,在运用中的其他部分能够经过调用Provider.of来获取同享数据。这种办法在大型运用中能够更好地安排和办理数据,而且减少了冗余的代码和组件之间的耦合。
3.Provider类型
除了ChangeNotifierProvider和StreamProvider外,Provider还供给了一些其他类型的Provider,以满意不同的数据同享需求。这些包括:
- ValueListenableProvider:用于同享支撑监听的值列表。它能够监听ValueListenable对象的改变,并在改变时更新依赖于该值的UI部分。
- FutureProvider:用于同享异步操作的成果。它能够包装一个Future,并在Future完结时更新UI。
- ProxyProvider:用于根据其他Provider的值动态生成新的数据。它能够接收其他Provider的值,并根据这些值生成一个新的数据,并将其同享给依赖的UI部分。
- MultiProvider:用于在一个组件中同享多个不同类型的Provider。它能够简化在一个组件中运用多个Provider的状况。
除了这些内置的Provider类型,Provider还供给了一些辅佐类和功用,以便更好地安排和办理同享数据。例如:
- Provider.of:用于从Provider中获取同享数据。
- Provider.listen:用于监听同享数据的改变。
- Consumer和Selector:用于在UI中订阅同享数据的改变,并更新相应的UI。
总结起来,Provider是一个功用强大的状况办理库,它供给了多种类型的Provider来满意不同的数据同享需求,并经过一些辅佐类和功用来协助咱们更好地安排和办理同享数据。
4.ChangeNotifierProvider事例
假设咱们有一个计数器运用程序,需要同享一个计数器值给UI部分。咱们能够创立一个名为Counter的ChangeNotifier类来代表计数器的状况。
class Counter extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
接下来,咱们能够在顶层运用ChangeNotifierProvider封装咱们的Counter实例,以便在整个运用程序中同享该实例。在此示例中,咱们将在MaterialApp的顶层widget中运用Provider
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => Counter(),
child: MaterialApp(
title: 'Counter App',
home: HomePage(),
),
);
}
}
现在,咱们能够在UI部分运用Provider.of来获取同享的Counter实例,并根据需要更新UI。
`class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context);
return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 24),
),
SizedBox(height: 16),
RaisedButton(
onPressed: () {
counter.increment();
},
child: Text('Increment'),
),
],
),
),
);
}
}`
final counter = Provider.of(context);当你调用Provider.of办法时,默许状况下它会将listen参数设置为true,这意味着它将测验在找不到数据模型时监听数据模型的改变,以便在数据发生改变时从头构建相关的部件。
可是,假如你不希望监听数据模型的改变,能够将listen参数设置为false。这样,当你调用Provider.of(context, listen: false)时,它将返回最近的父级数据模型而不会监听其改变。这对于一些只需要获取数据模型一次而不需要实时监听改变的状况非常有用。
Consumer
`Consumer<Counter>(
builder: (context, counter, child) {
return Text(
'Count: ${counter.count}',
style: TextStyle(fontSize: 24),
); }, ),`
咱们运用Consumer部件来订阅Counter的改变,替换final counter = Provider.of(context);。在builder函数中,咱们能够直接拜访Counter实例并根据需要构建UI。这样,在Counter的状况发生改变时,只有与Counter相关的部分会从头构建。
Selector
class CounterModel {
int counter;
CounterModel(this.counter);
}
// Selector的selector函数
int counterSelector(CounterModel model) => model.counter;
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Selector<CounterModel, int>(
selector: (context, model) => counterSelector(model),
builder: (context, counter, _) {
return Column(
children: [
Text('Counter: $counter'),
RaisedButton(
child: Text('Increment'),
onPressed: () {
Provider.of<CounterModel>(context, listen: false).counter++;
},
),
RaisedButton(
child: Text('Decrement'),
onPressed: () {
Provider.of<CounterModel>(context, listen: false).counter--;
},
),
],
);
},
);
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(0),
child: MyWidget(),
),
);
}`
在上面的例子中,咱们界说了一个CounterModel类来表示计数器的状况。咱们运用Selector组件来监听CounterModel的改变,并按需重建MyWidget。咱们经过传递一个selector函数来指定咱们所需的计数器值。当counter发生改变时,Selector将调用builder函数来构建新的Widget
Provider.listen
`void main() {
runApp(
ChangeNotifierProvider<CounterModel>(
create: (context) => CounterModel(),
child: MyWidget(), ), );
// 运用Provider.listen监听同享数据的改变
Provider.of<CounterModel> (context,listen:false).addListener((counterModel) {
// 在同享数据发生改变时进行相应的操作
print('CounterModel改变了:${counterModel.counter}'
); }); }`
假如咱们想要监听同享数据的改变并在数据发生改变时进行相应的操作,能够运用Provider.listen办法。
5.StreamProvider
- 实时谈天运用:StreamProvider能够用来办理和同享表示用户谈天数据的流。当谈天数据更新时,StreamProvider会主动告诉相关的监听者,并更新UI。
- 股票市场运用:StreamProvider能够用来办理和同享代表股票价格的流。当股票价格更新时,StreamProvider会主动告诉相关的监听者并更新UI。这能够用于显示实时的股票价格变化。
运用NotifyProvider也能够完结类似的功用,但它的主要用途是在运用程序的不同组件之间同享状况,并告诉监听者更新。在股票市场运用中,虽然咱们也能够运用NotifyProvider来办理股票价格的状况,并在价格变化时告诉监听者更新UI,但运用StreamProvider可能更合适处理实时数据流的状况。
` class Stock {
String symbol;
double price;
Stock({this.symbol, this.price});
}`
咱们能够创立一个StockStreamProvider类来办理和同享股票价格的流。它能够供给订阅(subscribe)和撤销订阅(unsubscribe)特定股票的办法,并在价格更新时告诉监听者:
class StockStreamProvider {
StreamController<Stock> _streamController=StreamController<Stock>();
void subscribe(String symbol) {
// 订阅特定股票的价格变化
// 这儿能够经过一些办法获取实时的股票价格,比如连接股票交易所的API
// 假设咱们假定的获取价格的办法是getStockPrice(symbol)
var stockPriceStream = getStockPrice(symbol);
// 监听价格变化,将变化的股票信息增加到流中
stockPriceStream.listen((price) {
var stock = Stock(symbol: symbol, price: price);
_streamController.add(stock);
});
}
void unsubscribe(String symbol) {
// 撤销订阅特定股票的价格变化
// 这儿能够根据需要封闭连接或撤销监听
// 假设咱们假定的撤销订阅的办法是
cancelStockPriceSubscription(symbol)
cancelStockPriceSubscription(symbol);
}
Stream<Stock> get stockStream => _streamController.stream;
}
最终,咱们能够在UI部分运用StreamProvider来订阅股票价格的流,并在价格变化时更新UI。假设咱们在Flutter中运用StreamBuilder来构建UI:
`StreamBuilder<Stock>(
stream: stockStreamProvider.stockStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
var stock = snapshot.data;
return Text('${stock.symbol}: \$${stock.price}');
} else {
return Text('Loading...');
}
},
);`
当股票价格流发生改变时,StreamProvider会主动告诉StreamBuilder,并将最新的股票价格传递给它。然后,StreamBuilder会根据股票价格的改变来更新UI,显示实时的股票价格变化。
MultiProvider
// 创立一个MultiProvider
MultiProvider multiProvider = new MultiProvider();
// 创立并增加多个数据源
DataSource salesDataSource = new SalesDataSource();
multiProvider.addDataSource(salesDataSource);
DataSource inventoryDataSource = new InventoryDataSource();
multiProvider.addDataSource(inventoryDataSource);
DataSource customerDataSource = new CustomerDataSource();
multiProvider.addDataSource(customerDataSource);
// 获取多个数据源的数据
List<Data> salesData = multiProvider.getData(salesDataSource);
List<Data> inventoryData = multiProvider.getData(inventoryDataSource);
List<Data> customerData = multiProvider.getData(customerDataSource);
// 根据需要处理数据
// 比如能够将销售数据、库存数据和客户数据整合在一起进行剖析 和报告生成
List<Data> integratedData = new ArrayList<>();
integratedData.addAll(salesData);
integratedData.addAll(inventoryData);
integratedData.addAll(customerData);
// 对整合后的数据进行处理和剖析
// ...
// 获取特定数据源的数据
List<Data> specificData = multiProvider.getData(salesDataSource);
// 根据需要更新数据源
multiProvider.updateDataSource(salesDataSource, newData);
// 删去数据源
multiProvider.removeDataSource(inventoryDataSource);
MultiProvider
能够用于任何需要从多个数据源中提取和整合数据的场景,以完结数据的集成和同享,然后供给更全面和归纳的信息供用户进行剖析和决议计划
ProxyProvider
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<CartProvider>(
create: (_) => CartProvider(),
),
ProxyProvider<CartProvider, int>(
update: (_, cartProvider, __) => cartProvider.cart.items.length * 10,
// ProxyProvider经过update回调函数主动核算购物车总价
),
],
child: MaterialApp(
title: 'ProxyProvider Example',
home: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ProxyProvider Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Cart Total: ${context.watch<int>()}', // 从ProxyProvider获取购物车总价
style: TextStyle(fontSize: 24),
),
ElevatedButton(
onPressed: () {
context.read<CartProvider>().addItemToCart(0); // 增加商品到购物车
},
child: Text('Add Item to Cart'),
),
],
),
),
);
}
}
运用ChangeNotifierProvider创立CartProvider实例,并经过ProxyProvider来获取购物车总价。在HomePage中,咱们运用context.watch()来获取购物车总价,并在增加商品到购物车时,调用context.read().addItemToCart()来更新购物车数据,并主动从头核算购物车总价。
小结
运用办法总结差不多了,五分钟往后阅览别人的provider代码能够变得明晰,根据需要挑选合适自己的运用风格。