使用 shared_preferences 在启动时获取主题

Use shared_preferences to get theme at startup

如果对 shared_preferences 的所有调用都是异步的,我如何根据存储在 shared_preferences 中的内容设置我的应用程序的主题?

例如,我有一个 ThemeServiceshared_preferences 和 returns 中查找设置的主题,这适用于在 UI 中切换它,但我如何在启动时加载它?

class ThemeService {

  static String key = "isDark";

  /// Return the ThemeData based on what is persisted.
  Future<ThemeData> getTheme() async {
    final prefs = await SharedPreferences.getInstance();

    final isDarkMode = prefs.getBool(key) ?? false;

    if (isDarkMode) {
      return ThemeDark().theme;
    } else {
      return ThemeLight().theme;
    }
  }

  /// Toggle the theme between light/dark and persist the chosen value.
  Future<void> toggleTheme() async {
    final prefs = await SharedPreferences.getInstance();

    final isDarkMode = prefs.getBool(key) ?? false;

    if (isDarkMode) {
      Get.changeTheme(ThemeLight().theme);
      await prefs.setBool(key, false);
    } else {
      Get.changeTheme(ThemeDark().theme);
      await prefs.setBool(key, true);
    }
  }
}

我希望能够这样使用它:

class App extends StatelessWidget {

  final ThemeService themeService = Get.find<ThemeService>();

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
        debugShowCheckedModeBanner: false,
        initialBinding: InitialBinding(),
        initialRoute: initialRoute(),
        theme: themeService.getTheme(), // Its a future, so can't do this...
        getPages: AppPages.routes);
  }
}

Flutter 新手,我是不是错过了一个概念或模式?有什么方法我应该访问不需要 async/await 的首选项吗?

如评论中所建议,解决方案是将 GetMaterialApp 包装在 FutureBuilder

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<ThemeData>(
        future: ThemeService().getTheme(),
        builder: (BuildContext context, AsyncSnapshot<ThemeData> snapshot) {
          return GetMaterialApp(
              debugShowCheckedModeBanner: false,
              initialBinding: InitialBinding(),
              initialRoute: initialRoute(),
              theme: snapshot.data,
              darkTheme: darkTheme,
              getPages: AppPages.routes);
        });
  }

我个人会让 main 异步。所以代码会更像:

void main() async {
  final themeService = ThemeService();
  final initialTheme = await themeService.getTheme();
  
  runApp(App(initialTheme: initialTheme));
}

class App extends StatelessWidget {
  
  final ThemeData initialTheme;

  const App({Key? key, this.initialTheme}) : super(key: key); 

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
        debugShowCheckedModeBanner: false,
        initialBinding: InitialBinding(),
        initialRoute: initialRoute(),
        theme: initialTheme, // <-- Now can do it
        getPages: AppPages.routes);
  }
}