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

如何在Flutter中结合SharedPreferences持久化数据初始化GoRouter

Flutter中GoRouter初始路径依赖异步SharedPreferences的解决方案

针对你遇到的「路由初始路径需要异步读取SharedPreferences,但无法在build/main中直接await」的问题,Flutter社区常用以下几种方案解决:

方案1:用启动页(Splash Screen)做过渡初始化

启动时先显示一个加载页(可加动画),在该页面的生命周期中完成SharedPreferences的读取,再通过GoRouter跳转到对应页面:

class SplashPage extends StatefulWidget {
  const SplashPage({super.key});

  @override
  State<SplashPage> createState() => _SplashPageState();
}

class _SplashPageState extends State<SplashPage> {
  @override
  void initState() {
    super.initState();
    _navigateToTargetPage();
  }

  Future<void> _navigateToTargetPage() async {
    // 异步读取偏好设置
    final prefs = await SharedPreferences.getInstance();
    final hasCompletedOnboarding = prefs.getBool('has_completed_onboarding') ?? false;

    // 确保组件未被销毁再跳转
    if (!mounted) return;
    
    if (hasCompletedOnboarding) {
      context.go('/home');
    } else {
      context.go('/onboarding');
    }
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      body: Center(child: CircularProgressIndicator()), // 加载动画
    );
  }
}

然后将GoRouter的initialLocation设为/splash,并添加对应路由:

GoRouter(
  initialLocation: '/splash',
  routes: [
    GoRoute(path: '/splash', builder: (context, state) => const SplashPage()),
    GoRoute(path: '/onboarding', builder: (context, state) => const OnboardingPage()),
    GoRoute(path: '/home', builder: (context, state) => const HomePage()),
  ],
);

方案2:利用GoRouter的异步redirect机制

GoRouter支持异步的redirect回调,你可以提前定义一个全局的SharedPreferences Future,在redirect中等待它完成后决定跳转路径:

// 全局定义,提前初始化Future(不会阻塞main)
final prefsFuture = SharedPreferences.getInstance();

final router = GoRouter(
  initialLocation: '/loading',
  routes: [
    GoRoute(path: '/loading', builder: (context, state) => const LoadingPage()),
    GoRoute(path: '/onboarding', builder: (context, state) => const OnboardingPage()),
    GoRoute(path: '/home', builder: (context, state) => const HomePage()),
  ],
  redirect: (context, state) async {
    // 等待SharedPreferences实例获取完成
    final prefs = await prefsFuture;
    final hasCompletedOnboarding = prefs.getBool('has_completed_onboarding') ?? false;

    // 仅在加载页时触发跳转判断
    if (state.location == '/loading') {
      return hasCompletedOnboarding ? '/home' : '/onboarding';
    }
    return null; // 返回null表示不跳转
  },
);

方案3:用FutureBuilder作为根组件

直接将App的根组件设为FutureBuilder,等待SharedPreferences加载完成后再初始化GoRouter:

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<SharedPreferences>(
      future: SharedPreferences.getInstance(),
      builder: (context, snapshot) {
        // 未加载完成时显示加载页
        if (snapshot.connectionState != ConnectionState.done) {
          return const MaterialApp(home: LoadingPage());
        }

        // 加载完成后初始化路由
        final prefs = snapshot.data!;
        final initialPath = prefs.getBool('has_completed_onboarding') ?? false 
            ? '/home' 
            : '/onboarding';

        return MaterialApp.router(
          routerConfig: GoRouter(
            initialLocation: initialPath,
            routes: [
              GoRoute(path: '/onboarding', builder: (context, state) => const OnboardingPage()),
              GoRoute(path: '/home', builder: (context, state) => const HomePage()),
            ],
          ),
        );
      },
    );
  }
}

为什么直接异步main不行?

main()中直接await SharedPreferences.getInstance()会报错,因为此时Flutter的平台通道尚未初始化完成,SharedPreferences依赖平台原生存储实现,必须在runApp()启动Flutter引擎后才能正常访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:35:32