Flutter应用启动时如何通过shared_preferences读取存储的主题并设置
解决方案
方案1:启动前置初始化(最推荐,适配你的现有技术栈)
你遇到的核心矛盾是SharedPreferences读写是异步,而GetMaterialApp的theme参数需要同步值,最简单的解决方式是把主题读取逻辑提前到runApp执行之前完成,步骤如下:
- 改造
ThemeService,增加同步可访问的当前主题属性和初始化方法:
class ThemeService { static String key = "isDark"; // 同步可访问的当前主题变量 late ThemeData currentTheme; // 缓存SharedPreferences实例,避免重复初始化 late SharedPreferences _prefs; // 启动时调用一次的初始化方法 Future<void> init() async { _prefs = await SharedPreferences.getInstance(); final isDarkMode = _prefs.getBool(key) ?? false; currentTheme = isDarkMode ? ThemeDark().theme : ThemeLight().theme; } /// 切换深浅主题并持久化存储选择结果 Future<void> toggleTheme() async { final isDarkMode = _prefs.getBool(key) ?? false; if (isDarkMode) { currentTheme = ThemeLight().theme; Get.changeTheme(ThemeLight().theme); await _prefs.setBool(key, false); } else { currentTheme = ThemeDark().theme; Get.changeTheme(ThemeDark().theme); await _prefs.setBool(key, true); } } /// 保留原有getTheme方法按需使用 Future<ThemeData> getTheme() async { final isDarkMode = _prefs.getBool(key) ?? false; return isDarkMode ? ThemeDark().theme : ThemeLight().theme; } }
- 改造main函数,提前完成初始化再启动应用:
void main() async { // 必须调用这行,确保Flutter渲染绑定初始化完成后再执行异步操作 WidgetsFlutterBinding.ensureInitialized(); // 提前初始化ThemeService,读取持久化的主题配置 final themeService = ThemeService(); await themeService.init(); // 将初始化完成的ThemeService存入Get容器,后续全局可访问 Get.put(themeService); // 所有前置初始化完成后再启动App runApp(const App()); }
- 改造App类,直接使用同步的主题属性:
class App extends StatelessWidget { final ThemeService themeService = Get.find<ThemeService>(); @override Widget build(BuildContext context) { return GetMaterialApp( debugShowCheckedModeBanner: false, initialBinding: InitialBinding(), initialRoute: initialRoute(), // 直接使用同步的currentTheme,不再是Future类型 theme: themeService.currentTheme, getPages: AppPages.routes); } }
这个方案逻辑简单,没有额外的状态判断,适合绝大多数应用场景。
方案2:启动时用FutureBuilder异步等待
如果你不想卡住启动流程,或者需要在加载主题时展示启动屏,可以用FutureBuilder包裹GetMaterialApp,等异步读取主题完成后再渲染主应用:
class App extends StatelessWidget { final ThemeService themeService = Get.find<ThemeService>(); @override Widget build(BuildContext context) { return FutureBuilder<ThemeData>( future: themeService.getTheme(), builder: (context, snapshot) { // 异步读取完成后渲染主应用 if (snapshot.connectionState == ConnectionState.done) { return GetMaterialApp( debugShowCheckedModeBanner: false, initialBinding: InitialBinding(), initialRoute: initialRoute(), theme: snapshot.data!, getPages: AppPages.routes, ); } // 读取中展示自定义启动屏/加载占位 else { return const MaterialApp( home: Scaffold( body: Center(child: CircularProgressIndicator()), ), ); } }, ); } }
疑问解答
有没有不需要async/await就可以访问偏好存储的方法?
官方的shared_preferences库本身没有提供同步读写接口,因为它本质是读写本地磁盘文件,异步是默认的实现逻辑。如果你需要同步读写能力,可以使用和GetX生态适配良好的get_storage库,它采用内存缓存+本地持久化的实现,初始化完成后就可以同步读写持久化数据。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

