我有几个保留在SharedPreferences中的帐户,并且想要使当前帐户(用户在对话框中选择)可以在整个应用程序中访问。当用户更改当前帐户时,UI应自动更新以显示该帐户。但是,当当前用户更改时,我尝试过的应用程序状态系统不会更新StatefulWidgets。
我尝试了SharedPreferences,InheritedWidget,Provider和ChangeNotifier。我无法收听SharedPreferences的更改,其他解决方案也无法在状态更改时更新UI。
// Main.dart
void main() => runApp(
ChangeNotifierProvider<AppStateManager>.value(
value: AppStateManager(),
child: MyApp()
)
);
class AppStateManager extends ChangeNotifier {
int _currentStudentIndex;
int get currentStudentIndex => _currentStudentIndex;
set currentStudentIndex(int index) {
_currentStudentIndex = index;
notifyListeners();
}
}
// Code that runs when the user selects a new account
onPressed: () {
Provider.of<AppStateManager>(context).currentStudentIndex = index;
Navigator.pop(context);
},
// The state for my StatefulWidget
_TodayState() {
getCurrentStudent().then((student) => setState(() {
_currentStudent = student;
}));
}
Future<Student> getCurrentStudent() async {
List<String> students = await PreferencesManager.getStudents();
final AppStateManager stateManager = Provider.of<AppStateManager>(context);
Map<String, dynamic> currentStudent = jsonDecode(students[stateManager.currentStudentIndex ?? 0]);
return Student.fromJson(currentStudent);
}
答案 0 :(得分:2)
我尝试通过提供的代码段重新创建您的代码,并且可能会重现您的问题(here)。您已正确设置状态并调用notifyListeners()
,但未在构建方法中使用状态。您假设_TodayState
每次看到都被构造,但这是不正确的。例如,Flutter会将其保存在内存中(如果它处于活动堆栈中)(例如,当您将导航器路线推到顶部时)。
换句话说,构造函数代码(getCurrentStudent().then(...)
)的执行频率不如您想象的那样。
为确保您的UI得到更新,请将内容放入build()
方法中。例如:
Consumer<AppStateManager>(
builder: (context, manager, child) => FutureBuilder<Student>(
future: getCurrentStudent(manager.currentStudentIndex),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const CircularProgressIndicator();
}
return Text('Student: ${snapshot.data.name}');
},
),
),
这有效。 Here是要点。每当状态改变时,它确实会获取学生,这可能是您想要的,也可能不是。
如果您绝对需要混合使用setState
,future和InheritedWidgets,则可能需要手动监听提供的值(使用类似stateManager.addListener(listener)
的值)。但是最好避免这种情况,因为它可能是错误的来源。
作为Provider的一般建议:在构建方法中(使用Consumer<...>
或Provider.of<...>
收听它,而不是其他任何地方。