У меня есть приложение с рабочей регистрацией пользователя, и с помощью поставщика пользователей я могу без проблем настроить пользователя во время регистрации и получить его на следующем экране. У меня возникли проблемы с попыткой правильно реализовать возможность установки сохраненного в данный момент пользователя, вошедшего в систему, при запуске приложения и перейти к панели управления, а не проходить процесс регистрации, не выдавая нижеприведенное утверждение.
Я могу получить пользователя из 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 я попытался связать then с вызовом getUserData()
, чтобы установить пользователя, однако это, конечно, возвращает следующее утверждение:
════════ 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();
}
}
Как я могу правильно настроить пользователя, когда приложение загружается, если кто-то уже вошел в систему, не выполняя приведенное выше утверждение? Спасибо!