initialRoute 字符串已更改,但无论 initialRoute 字符串如何,我最终都会到达同一页面

initialRoute string is changed, but I end up at the same page regardless the initialRoute string

当在 main.dart 的 flutter 上使用 shared_preferences 以根据用户是否看到第一页或用户是否登录来更改 initialRoute 时,我得到了在整个过程中创建的布尔值应用程序并添加到 shared_preferences,每次我启动应用程序时,调试时我都会得到正确的 initialRoute 字符串,但无论条件如何,我最终还是会进入第一页。

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:developer';

import './pages/registration.dart';
import './pages/login_page.dart';
import './pages/confirmation.dart';
import './pages/lang_page.dart';
import './pages/main_page.dart';
import './pages/user_data.dart';
import './provider/provider.dart';

void main() => runApp(CallInfoApp());

class CallInfoApp extends StatefulWidget {
  @override
  _CallInfoAppState createState() => _CallInfoAppState();
}

class _CallInfoAppState extends State<CallInfoApp> {
  SharedPreferences prefs;

  void getSPInstance() async {
    prefs = await SharedPreferences.getInstance();
  }

  dynamic langChosen;
  dynamic isLoggedIn;
  String initialRoute;

  void dataGetter() async {
    await getSPInstance();
    setState(() {
      langChosen = prefs.getBool('langChosen');
      // print(langChosen);
      isLoggedIn = prefs.getBool('isLoggedIn');
    });
  }

  void getRoute() async {
    await dataGetter();
    debugger();
    if (langChosen == true && isLoggedIn != true) {
      setState(() {
        initialRoute = '/login_page';
      });
    } else if (isLoggedIn == true) {
      initialRoute = '/main_page';
    } else {
      setState(() {
        initialRoute = '/';
      });
    }
  }

  @override
  void initState() {
    super.initState();
    debugger();
    getRoute();
  }

  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitUp,
      DeviceOrientation.portraitDown,
    ]);

    return ChangeNotifierProvider<AppData>(
      create: (context) => AppData(),
      child: MaterialApp(
        title: 'Call-INFO',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        initialRoute: initialRoute,
        routes: {
          '/': (context) => LanguagePage(),
          '/registration_page': (context) => RegistrationPage(),
          '/login_page': (context) => LoginPage(),
          '/confirmation_page': (context) => ConfirmationPage(),
          '/user_data_page': (context) => UserDataPage(),
          '/main_page': (context) => MainPage(),
        },
      ),
    );
  }
}

使用 initState 导出您的逻辑所基于的数据(即获取共享偏好信息)。并使用 await 关键字,以便程序将等待数据从 SharedPrefs 中获取。将以下代码添加到 class _CallInfoAppState 应该会有所帮助

@override
  void initState() {
    super.initState();
    dataGetter();
  }

void dataGetter() async {
    await getSPInstance();
    setState(() {
      langChosen = prefs.getBool('langChosen');
      isLoggedIn = prefs.getBool('isLoggedIn');
    });
  }

由于 SharedPreference.getInstance() 是一个异步函数,它需要一些时间才能使实例可用。如果你想将它用于初始路由,你必须在你的 MaterialApp 构建之前让你的主函数异步并预加载它。

SharedPreference prefs; //make global variable, not best practice
void main() async {
   prefs = await SharedPreference.getInstance();
   runApp(CallInfoApp());
}

并从 dataGetter 中删除 getSPInstance()

另外请注意,如果没有条目进入共享首选项,prefs.getBool('langChosen') 将 return 为 null 而不是 false,因此请使用

langChosen = prefs.getBool('langChosen')??false;
isLoggedIn = prefs.getBool('isLoggedIn')??false;

虽然此解决方案可行,但并不是很好的做法。我建议将 initialRoute 固定到初始屏幕并从那里处理转发到正确的页面。一个简单的启动画面可能如下所示:

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(body: Center(child: CircularProgressIndicator()));
  }

  @override
  void initState() {
    initSplash();
    super.initState();
  }

  Future<void> initSplash() async {
    final prefs = await SharedPreferences.getInstance();
    final langChosen = prefs.getBool("lang_chosen") ?? false;
    final isLoggedIn = prefs.getBool("logged_in") ?? false;

    if (langChosen == true && isLoggedIn != true) {
      Navigator.of(context).pushReplacementNamed('/login_page');
    } else if (isLoggedIn == true) {
      Navigator.of(context).pushReplacementNamed('/main_page');
    } else {
      Navigator.of(context).pushReplacementNamed('/');
    }
  }
}