flutter - 不确定如何正确实现 ChangeNotifierProvider 以记住 Flutter 中的登录用户
问题描述
我有一个具有工作用户注册的应用程序,并且使用用户提供程序可以在注册期间设置用户并在以下屏幕上检索它而不会出现问题。我遇到的问题是尝试正确实现在应用程序启动时设置存储的当前登录用户并进入仪表板的能力,而不是在不抛出以下断言的情况下完成注册过程。
我可以毫无问题地获取用户,SharedPreferences
但是我不确定如何在我的提供程序中正确设置此用户,以便在仪表板屏幕加载时可以访问它。下面是我的main()
函数和 MyApp 类。
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => AuthProvider()),
ChangeNotifierProvider(create: (context) => UserProvider()),
],
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
Future<User> getUserData() => UserPreferences().getUser();
return MaterialApp(
title: 'My App',
theme: ThemeData(
primarySwatch: Colors.red,
accentColor: Colors.black,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FutureBuilder(
future: getUserData().then((value) => {
Provider.of<UserProvider>(context, listen: false)
.setUser(value)
}),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return CircularProgressIndicator();
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else if (snapshot.data.token == null)
return Login();
else if (snapshot.data.token != null) {
return Dashboard();
} else {
UserPreferences().removeUser();
return Login();
}
}
}),
routes: {
'/dashboard': (context) => Dashboard(),
'/login': (context) => Login(),
'/register': (context) => Register(),
'/username': (context) => Username(),
});
}
}
在 FutureBuilder 中,我尝试在getUserData()
调用上链接一个 then 来设置用户,但这当然会返回以下断言:
════════ Exception caught by foundation library ════════════════════════════════
The following assertion was thrown while dispatching notifications for UserProvider:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<UserProvider> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
从我读过的内容来看,这是因为notifyListeners()
在用户提供程序中有一个调用,它将调用markNeedsBuild()
. 也就是说,我已经尝试在网上移动一些东西和一些建议,但无法弄清楚实现这一点的最佳实践和最佳方法是什么。
用户提供者:
class UserProvider with ChangeNotifier {
User _user = new User();
User get user => _user;
void setUser(User user) {
_user = user;
notifyListeners();
}
}
如果有人已经登录而没有遇到上述断言,我如何在应用程序加载时正确设置用户?谢谢!
解决方案
共享偏好可按如下方式使用:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
body: Center(
child: RaisedButton(
onPressed: _incrementCounter,
child: Text('Increment Counter'),
),
),
),
));
}
_incrementCounter() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
int counter = (prefs.getInt('counter') ?? 0) + 1;
print('Pressed $counter times.');
await prefs.setInt('counter', counter);
}
推荐阅读
- python - 如何在 (for item in list) 循环内访问列表的下一项?(Python 3)
- php - 仅在某些智能手机上输出缓冲区 php 时出现白屏
- r - 随着 y 值的增加重新排序 ggplot 条形图
- php - 从 laravel 中的数据库动态填充语言翻译数组
- vhdl - 是否有命令修改modelsim中的整数范围
- python - 如何在不附加键的情况下将字典附加到 csv
- javascript - OnClick 下拉菜单的位置错误
- javascript - WebGL:使用不同的程序渲染大量对象
- tensorflow - 未知形状张量流中的空间金字塔池化
- windows - Azure 容器中的 Windows 服务无法启动