Flutter中ChangeNotifier子类初始化主题状态失败求助
问题原因及解决方案
你的代码存在两个核心问题,导致主题初始化失效:
1. 异步初始化未触发UI更新
init()方法修改_isDarkMode后,没有调用notifyListeners(),Consumer无法感知状态变化,UI会一直停留在初始的深色模式(默认值_isDarkMode = true)。
2. 异步初始化未等待完成
在ChangeNotifierProvider的create方法中调用prefs.init()时,没有等待异步操作完成就返回了实例。此时UI已经基于初始值渲染,后续初始化完成后也不会触发UI重建。
修复步骤:
第一步:更新PreferencesModel的init方法
添加notifyListeners()通知UI状态变化:
class PreferencesModel extends ChangeNotifier { static const _darkModeSetting = "darkmode"; bool _isDarkMode = true; // default, overridden by init() bool get isDarkMode => _isDarkMode; ThemeData get appTheme => _isDarkMode ? AppThemes.darkTheme : AppThemes.lightTheme; void init() async { final prefs = await SharedPreferences.getInstance(); final bool? dark = prefs.getBool(_darkModeSetting); _isDarkMode = dark ?? false; await prefs.setBool(_darkModeSetting, _isDarkMode); notifyListeners(); // 新增:通知UI更新最新状态 } void setDarkMode(bool isDark) async { print("setting preferences dark mode to ${isDark}"); final prefs = await SharedPreferences.getInstance(); await prefs.setBool(_darkModeSetting, isDark); _isDarkMode = isDark; notifyListeners(); } }
第二步:确保初始化完成后再启动App
修改main函数,先等待PreferencesModel初始化完成再运行App:
void main() async { // 必须调用此方法,才能在main函数中使用异步操作 WidgetsFlutterBinding.ensureInitialized(); final prefsModel = PreferencesModel(); await prefsModel.init(); // 等待初始化完成 runApp( MultiProvider( providers: [ ChangeNotifierProvider.value(value: prefsModel), ], child: const MyApp(), ) ); }
可选方案:用FutureBuilder处理加载状态
如果不想阻塞App启动,可以在MyApp中用FutureBuilder显示加载界面,等待初始化完成后再渲染主题:
class _MyAppState extends State<MyApp> { late Future<void> _initFuture; @override void initState() { super.initState(); // 获取Provider实例并启动初始化,listen: false避免不必要的重建 _initFuture = Provider.of<PreferencesModel>(context, listen: false).init(); } @override Widget build(BuildContext context) { return FutureBuilder( future: _initFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { return Consumer<PreferencesModel>( builder: (context, preferences, child) { return MaterialApp( title: 'MyApp', home: MainPage(title: 'MyApp'), theme: AppThemes.lightTheme, darkTheme: AppThemes.darkTheme, themeMode: preferences.isDarkMode ? ThemeMode.dark : ThemeMode.light, ); } ); } else { // 初始化过程中显示加载动画 return const Center(child: CircularProgressIndicator()); } }, ); } }
内容的提问来源于stack exchange,提问作者senseiwa
相关产品推荐
相关产品推荐

