flutter provider create: (_) => xxxx(),
Provider通常使用ChangeNotifierProvider配合ChangeNotifier一起来实现状态的管理与Widget的更新。
ChangeNotifierProvider本质上其实就是Widget,它作为父节点Widget,可将数据共享给其所有子节点Widget使用或更新;
-
创建model,继承ChangeNotifier,用来实现数据更新的通知并监听数据的变化
-
调用notifyListeners()通知给监听方
-
创建ChangeNotifierProvider,用来声明Provider,实现跨组建的数据共享;
-
用ChangeNotifierProvider将父布局包裹,在父或子节点ChildA通过Provider.of<T>(BuildContext context, {bool listen = true})进行数据操作,
可同步更新父与子的数据与UI。其中listen默认为true可监听数据的变化,为false的情况只可读取数据的值
-
接收共享数据;context.watch<>()和context.read<>()
-
不管是在父节点还是在子节点,都可以对ProviderViewModel的数据进行操作和监听。
例1在操作与读取时使用的是Provider.of<T>(BuildContext context, {bool listen = true})的方式,
为了可以更明确对于Provider的操作,我们可将它替换为context.watch<>()和context.read<>()方式。
我们可以通过源码看到,context.watch<>()和context.read<>()方法其实都是调用Provider.of<T>(BuildContext context, {bool listen = true})来实现
pubspec.yaml 中引用
provider: ^6.0.3
在Flutter中,context.watch<T>()
和context.read<T>()
都是用于在Widget树中获取和监听状态的方法,它们都是来自于Flutter的状态管理库provider
。
-
context.watch<T>()
:该方法用于订阅状态变化,并在状态发生变化时重新构建相关的Widget。当使用context.watch<T>()
订阅某个类型为T
的状态时,如果该状态发生变化,与该状态相关的Widget会被重新构建。
final count = context.watch<Counter>().count;
在上面的示例中,我们使用context.watch<Counter>()
订阅了类型为Counter
的状态,当Counter
状态发生变化时,相关的Widget会重新构建,并获取最新的count
值。context.read<T>()
:该方法用于获取指定类型为T
的状态的当前值,而不会订阅状态的变化。如果在context.read<T>()
之前没有调用过相关状态的notifyListeners()
方法,那么获取到的将是状态的初始值。
final count = context.read<Counter>().count;
在上面的示例中,我们使用context.read<Counter>()
获取了类型为Counter
的状态的当前值。
总结:
- 如果您需要在状态发生变化时自动重新构建相关的Widget,请使用
context.watch<T>()
来订阅状态。 - 如果您只需要获取状态的当前值而不关心状态的变化,请使用
context.read<T>()
来获取状态。
请注意,context.watch<T>()
和context.read<T>()
都需要在Widget树中的BuildContext
上下文中使用。通常,您可以在构建方法中使用这些方法。
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; // Define a counter class as a ChangeNotifier class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } } void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (context) => Counter(), child: MaterialApp( home: HomePage(), ), ); } } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { final count = context.watch<Counter>().count; return Scaffold( appBar: AppBar( title: Text('Counter App'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Count: $count', style: TextStyle(fontSize: 24), ), ElevatedButton( onPressed: () { context.read<Counter>().increment(); }, child: Text('Increment'), ), ], ), ), ); } }
In this example, we define a Counter
class that extends ChangeNotifier
. It has a count
property and an increment
method that increases the count and notifies the listeners.
The MyApp
widget wraps the Counter
class with ChangeNotifierProvider
to make it available to the rest of the app.
In the HomePage
widget, we use context.watch<Counter>().count
to subscribe to changes in the Counter
state. Whenever the count
changes, the widget will be rebuilt to reflect the updated value. We also use context.read<Counter>().increment()
to call the increment
method of the Counter
class when the button is pressed.
This example demonstrates how to use context.watch<T>()
and context.read<T>()
to interact with state in Flutter using the provider
package.
The line ChangeNotifierProvider(create: (_) => userProvider)
is creating a provider for the userProvider
object.
Here's an example to illustrate its usage:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class User { final String name; final int age; User(this.name, this.age); } class UserProvider with ChangeNotifier { User _user; User get user => _user; void setUser(User user) { _user = user; notifyListeners(); } } void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ChangeNotifierProvider( create: (_) => UserProvider(), child: MaterialApp( home: HomePage(), ), ); } } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { final userProvider = Provider.of<UserProvider>(context); return Scaffold( appBar: AppBar( title: Text('User Info'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'Name: ${userProvider.user?.name ?? ''}', style: TextStyle(fontSize: 24), ), Text( 'Age: ${userProvider.user?.age ?? ''}', style: TextStyle(fontSize: 24), ), ElevatedButton( onPressed: () { final newUser = User('John Doe', 30); userProvider.setUser(newUser); }, child: Text('Set User'), ), ], ), ), ); } }
In this example, we have a User
class representing user information. The UserProvider
class is a ChangeNotifier
that manages the state of the current user.
The ChangeNotifierProvider
is created with create: (_) => UserProvider()
. It instantiates a new UserProvider
object and makes it available to the widget tree.
In the HomePage
widget, we use Provider.of<UserProvider>(context)
to access the UserProvider
instance. We can then use userProvider.user
to get the current user information and update it by calling userProvider.setUser(newUser)
.
By wrapping the HomePage
widget with ChangeNotifierProvider
, the UserProvider
state will be available to all the descendant widgets that depend on it. When the state changes, the corresponding widgets will be rebuilt to reflect the updated values.
In the context of the create
parameter in ChangeNotifierProvider
, the _
represents the build context argument that is not being used.
The _
is a convention used in Dart to indicate that a variable is intentionally unused. It's a way to communicate to other developers that the value of the variable is not relevant or necessary in the given context.
In the case of ChangeNotifierProvider
, the create
parameter expects a callback function that takes a build context argument. However, if the callback function does not require the build context, it is common to use _
as the variable name to indicate that it is intentionally unused.