You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于SharedPreference数据设置Flutter主题启动获取空值问题咨询

问题根因

SettingsSharedPreferences.getThemeString() 为同步返回方法,但内部读取SharedPreferences是异步IO操作,then回调执行前方法就已经返回了未赋值的theme变量,所以Provider初始化时拿到的主题值必然为null,异步读取完成后也没有触发UI更新,就导致首次启动主题不生效。

修复步骤

1. 修正SharedPreferences工具类

删掉错误的同步获取方法,统一异步逻辑,补全SharedPreferences实例获取的缺失逻辑:

class SettingsSharedPreferences {
  static const _keytheme = "theme";
  static const String _defaultTheme = "System";

  // 新增获取SharedPreferences实例的统一方法
  static Future<SharedPreferences> _getPrefs() async => await SharedPreferences.getInstance();

  static Future<void> setTheme(String theme) async {
    final prefs = await _getPrefs();
    await prefs.setString(_keytheme, theme);
  }

  static Future<String> getTheme() async {
    final prefs = await _getPrefs();
    final savedTheme = prefs.getString(_keytheme);
    if (savedTheme == null) {
      await setTheme(_defaultTheme);
      return _defaultTheme;
    }
    return savedTheme;
  }
}

2. 修正PreferencesProvider逻辑

给主题设默认值避免null,新增异步初始化方法读取本地存储,读取完成后通知更新:

class PreferencesProvider extends ChangeNotifier {
  // 先设置默认值为跟随系统,避免初始化时为null
  String theme = "System";

  PreferencesProvider() {
    _initTheme();
  }

  Future<void> _initTheme() async {
    final savedTheme = await SettingsSharedPreferences.getTheme();
    theme = savedTheme;
    notifyListeners();
  }

  // 新增修改主题的方法,修改后同步到本地存储并通知更新
  Future<void> updateTheme(String newTheme) async {
    theme = newTheme;
    await SettingsSharedPreferences.setTheme(newTheme);
    notifyListeners();
  }
}

3. 优化MyApp中的themeMode判断逻辑

减少重复的watch调用,逻辑更简洁:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final currentTheme = context.watch<PreferencesProvider>().theme;
    final ThemeMode themeMode;
    switch(currentTheme) {
      case "Dark":
        themeMode = ThemeMode.dark;
        break;
      case "Light":
        themeMode = ThemeMode.light;
        break;
      case "System":
      default:
        themeMode = ThemeMode.system;
        break;
    }
    return ChangeNotifierProvider<HabitProvider>(
      create: (context) => HabitProvider(),
      child: MaterialApp(
        darkTheme: ThemeData(brightness: Brightness.dark),
        themeMode: themeMode,
        home: MyHomePage(title: 'My App'),
      ),
    );
  }
}
可选优化:启动前预加载主题

如果不想出现启动后闪切主题的情况,可以在main函数中提前读取主题值再初始化Provider:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 提前读取主题
  final initTheme = await SettingsSharedPreferences.getTheme();
  runApp(ChangeNotifierProvider<PreferencesProvider>(
      create: (context) {
        return PreferencesProvider()..theme = initTheme;
      },
      child: MyApp()));
}

内容的提问来源于stack exchange,提问作者J0nathan Lam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 01:09:02