Provider 中的监听器在 Flutter 中是如何工作的?
How does listeners in Provider work in Flutter?
我正在使用 Provider 包来处理来自不同位置的数据。对于这个问题,我创建了一个示例项目,其中包含一个显示登录按钮的欢迎屏幕,单击后,它会重定向到登录屏幕,在那里会有登录文本字段,但现在,我已经放置了一个按钮,点击调用登录功能和登录功能通知听众。我还有一个注销函数和布尔值,用于跟踪登录状态。
这些函数和值驻留在 lib 文件夹的 providers 目录中名为 auth.provider.dart
的文件中。
import 'package:flutter/foundation.dart';
class Auth with ChangeNotifier {
var _loggedIn = false;
bool get loggedIn => _loggedIn;
void loginUser() {
_loggedIn = true;
print('Logged in');
notifyListeners();
}
void logout() {
_loggedIn = false;
print('Logged out');
notifyListeners();
}
}
我在 main.dart 中提供提供者,同时也在使用消费者:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Auth>(
create: (_) => Auth(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Consumer<Auth>(
builder: (_, auth, __) {
print('main.dart logged in: ${auth.loggedIn}');
if(auth.loggedIn) return HomeScreen();
return WelcomeScreen();
},
),
routes: {
LoginScreen.routeName: (ctx) => LoginScreen(),
HomeScreen.routeName: (ctx) => HomeScreen(),
},
),
);
}
}
在上面的文件中,我只是检查了loggedIn
是否为真。如果没有,则显示欢迎屏幕,以便用户可以登录,但如果用户已登录,则直接显示主屏幕。还在 Consumer 的构建器中放置了一个打印语句,以便在收到授权数据的任何更改通知时打印状态。这会在应用程序启动时运行一次,以后不会再运行。
登录界面内容不多,只有一个脚手架和一个调用登录功能的登录按钮。
RaisedButton(
child: Text('Click to Login'),
onPressed: () {
Provider.of<Auth>(context, listen: false).loginUser();
},
),
现在单击登录按钮时,它会将 loggedIn
布尔值设置为 true 并通知应该是 Consumer 的侦听器,但 main.dart 中的 Consumer 永远不会收到通知。它不会触发更改,有一个条件会检查登录是否为真,然后显示主屏幕但屏幕根本不会更改。必须手动使用 Navigator
移动到主屏幕,在主屏幕上有一个注销按钮,它只是将 loggedIn
设置为 false,一旦发生这种情况,它应该通知消费者,但它再次没有.
这让我想到了一个问题:Provider 中的侦听器是如何工作的?它什么时候通知监听器更改?如果更改发生的级别超过上例中的级别,它是否不会通知,消费者在 main.dart 中,并且更改发生在 main.dart > WelcomeScreen > LoginScreen
级别以下 2 级。如何让 main.dart
中的 Consumer 知道它正在使用的底层数据发生了变化?
如果你想快速上手上面的例子,here就是仓库link。
我查看了你的 github 代码。
使用 pushReplacementNamed 进入登录屏幕
Initially->main.dart->welcomeScreen->(on-clicking-loginbtn)->LoginScreen
这里,
1)消费者没有收听(因为您的初始 main.dart 屏幕已被登录页面取代,并且当前收听的页面上不存在)
2)没有导航器返回(因为页面被替换不在栈中)
使用 pushNamed 进入登录界面
Initially->main.dart->welcomeScreen->(on-clicking-loginbtn)->LoginScreen
这里,
1)消费者正在倾听(因为您的初始 main.dart 屏幕未被替换并存在于页面上 currently.But 您没有看到更改,因为您已经用登录屏幕覆盖了主初始页面在堆栈上方 )
2)有返回主屏幕的导航器(现在您可以使用后退箭头返回查看更改)
Conclusion Page will not able to listen to changed Provider Value if the page is replaced by other page. It should be there in a screen listening.
可以使用的模式
main.dart(家庭参数)
home: Consumer<Auth>(
builder: (_, auth, __) {
print('main.dart logged in: ${auth.loggedIn}');
if(auth.loggedIn) return HomeScreen();
return WelcomeScreen();
},
)
欢迎画面(登录码)
RaisedButton(
child: Text('Login'),
onPressed: () => Navigator.of(context).pushReplacementNamed(LoginScreen.routeName),
)
LoginScreen(登录按钮)
RaisedButton(
child: Text('Click to Login'),
onPressed: () {
Provider.of<Auth>(context, listen: false).loginUser();
Navigator.of(context).pushReplacementNamed('/');
},
)
主屏幕(注销 btn)
RaisedButton(
child: Text('Logout'),
onPressed: () {
Provider.of<Auth>(context, listen: false).logout();
Navigator.of(context).pushReplacementNamed('/');
}
我正在使用 Provider 包来处理来自不同位置的数据。对于这个问题,我创建了一个示例项目,其中包含一个显示登录按钮的欢迎屏幕,单击后,它会重定向到登录屏幕,在那里会有登录文本字段,但现在,我已经放置了一个按钮,点击调用登录功能和登录功能通知听众。我还有一个注销函数和布尔值,用于跟踪登录状态。
这些函数和值驻留在 lib 文件夹的 providers 目录中名为 auth.provider.dart
的文件中。
import 'package:flutter/foundation.dart';
class Auth with ChangeNotifier {
var _loggedIn = false;
bool get loggedIn => _loggedIn;
void loginUser() {
_loggedIn = true;
print('Logged in');
notifyListeners();
}
void logout() {
_loggedIn = false;
print('Logged out');
notifyListeners();
}
}
我在 main.dart 中提供提供者,同时也在使用消费者:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Auth>(
create: (_) => Auth(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Consumer<Auth>(
builder: (_, auth, __) {
print('main.dart logged in: ${auth.loggedIn}');
if(auth.loggedIn) return HomeScreen();
return WelcomeScreen();
},
),
routes: {
LoginScreen.routeName: (ctx) => LoginScreen(),
HomeScreen.routeName: (ctx) => HomeScreen(),
},
),
);
}
}
在上面的文件中,我只是检查了loggedIn
是否为真。如果没有,则显示欢迎屏幕,以便用户可以登录,但如果用户已登录,则直接显示主屏幕。还在 Consumer 的构建器中放置了一个打印语句,以便在收到授权数据的任何更改通知时打印状态。这会在应用程序启动时运行一次,以后不会再运行。
登录界面内容不多,只有一个脚手架和一个调用登录功能的登录按钮。
RaisedButton(
child: Text('Click to Login'),
onPressed: () {
Provider.of<Auth>(context, listen: false).loginUser();
},
),
现在单击登录按钮时,它会将 loggedIn
布尔值设置为 true 并通知应该是 Consumer 的侦听器,但 main.dart 中的 Consumer 永远不会收到通知。它不会触发更改,有一个条件会检查登录是否为真,然后显示主屏幕但屏幕根本不会更改。必须手动使用 Navigator
移动到主屏幕,在主屏幕上有一个注销按钮,它只是将 loggedIn
设置为 false,一旦发生这种情况,它应该通知消费者,但它再次没有.
这让我想到了一个问题:Provider 中的侦听器是如何工作的?它什么时候通知监听器更改?如果更改发生的级别超过上例中的级别,它是否不会通知,消费者在 main.dart 中,并且更改发生在 main.dart > WelcomeScreen > LoginScreen
级别以下 2 级。如何让 main.dart
中的 Consumer 知道它正在使用的底层数据发生了变化?
如果你想快速上手上面的例子,here就是仓库link。
我查看了你的 github 代码。
使用 pushReplacementNamed 进入登录屏幕
Initially->main.dart->welcomeScreen->(on-clicking-loginbtn)->LoginScreen
这里,
1)消费者没有收听(因为您的初始 main.dart 屏幕已被登录页面取代,并且当前收听的页面上不存在)
2)没有导航器返回(因为页面被替换不在栈中)
使用 pushNamed 进入登录界面
Initially->main.dart->welcomeScreen->(on-clicking-loginbtn)->LoginScreen
这里,
1)消费者正在倾听(因为您的初始 main.dart 屏幕未被替换并存在于页面上 currently.But 您没有看到更改,因为您已经用登录屏幕覆盖了主初始页面在堆栈上方 )
2)有返回主屏幕的导航器(现在您可以使用后退箭头返回查看更改)
Conclusion Page will not able to listen to changed Provider Value if the page is replaced by other page. It should be there in a screen listening.
可以使用的模式
main.dart(家庭参数)
home: Consumer<Auth>(
builder: (_, auth, __) {
print('main.dart logged in: ${auth.loggedIn}');
if(auth.loggedIn) return HomeScreen();
return WelcomeScreen();
},
)
欢迎画面(登录码)
RaisedButton(
child: Text('Login'),
onPressed: () => Navigator.of(context).pushReplacementNamed(LoginScreen.routeName),
)
LoginScreen(登录按钮)
RaisedButton(
child: Text('Click to Login'),
onPressed: () {
Provider.of<Auth>(context, listen: false).loginUser();
Navigator.of(context).pushReplacementNamed('/');
},
)
主屏幕(注销 btn)
RaisedButton(
child: Text('Logout'),
onPressed: () {
Provider.of<Auth>(context, listen: false).logout();
Navigator.of(context).pushReplacementNamed('/');
}