【问题标题】:Navigating away when a Flutter FutureProvider resolves it's future当 Flutter FutureProvider 解决它的未来时导航
【发布时间】:2019-10-31 07:32:13
【问题描述】:

我基本上是在寻找一种方法来开始加载数据或导航到登录屏幕。

FutureProvider 从 SharedPreferences 获得它的价值。默认主屏幕只是一个带有微调器的徽标。

如果用户 ID 解析为 null,则应用应导航到登录屏幕,否则应调用将开始加载数据的方法,然后在完成后导航到主页。

这可以通过 FutureProvider 实现吗?

我将它添加到页面构建中以确保页面小部件将订阅提供者:

  Widget build(BuildContext context) {
    userInfo = Provider.of<UserInfo>(context);
    print('Building with $userInfo'); 
    return PageWithLoadingIndicator();
....

我将它添加到 didChangeDependencies 以对更改做出反应:

  @override
  void didChangeDependencies() {
    print('Deps changed: $userInfo');
    super.didChangeDependencies();
//    userInfo = Provider.of<UserInfo>(context); // Already building, can't do this.
//    print('And now: $userInfo');
    if (userInfo == null) return;
    if (userInfo.userId != null) {
      startUp(); // Run when user is logged in
    } else {
      tryLogin(); // Navigate to Login 
    }
  }

因为我不能在 initState 中使用 Provider.of,所以我添加了一个 PostFrameCallback

  void postFrame(BuildContext context) {
    print('PostFrame...');
    userInfo = Provider.of<UserInfo>(context);
  }

Main 非常简单——它现在只是用一个 FutureProvider 设置 MultiProvider。

class MyApp extends StatelessWidget {

  Future<UserInfo> getUserInfo() async {
    String token = await UserPrefs.token;
    return UserInfo.fromToken(
      token,
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'App One',
      theme: ThemeData(
        primarySwatch: Colors.purple,
      ),
      home: MultiProvider(
        providers: [FutureProvider<UserInfo>(builder: (_) => getUserInfo())],
        child: LoadingScreen(),
      ),
    );
  }
}

问题在于,现在我可以从打印语句中看到“didChangeDependencies”被调用了两次,但 userInfo 的值始终为 null,即使 build() 最终获得了 UserInfo 的实例,如在 build() 方法中打印语句。

我猜我可以在 build 方法中添加一些逻辑,但这让我觉得做错了地方......也许它没有我想的那么糟糕?

【问题讨论】:

  • 您是否尝试调用 userInfo = Provider.of(context);在 didChangeDependencies 中?
  • 是的,你不能那样做。它会导致错误,因为 Build 已经在进行中。
  • 我认为问题在于Provider只想构建Widgets,而不是控制应用程序的流程。因此,现在在 initState 的这个页面上,我添加了一个对异步函数的调用,该函数将等待 sharedPreferences,然后导航离开或开始数据加载过程。

标签: flutter dependency-injection state


【解决方案1】:

我认为这在概念上是错误的方法。

就我而言,我想使用 FutureProvider 从使用 SharedPreferences 创建“配置”对象的异步函数中获取结果。然后,FutureProvider 将允许应用程序的其余部分访问从 sharepreferences 获得的用户配置设置。

这对我来说仍然是一种有效的方法。但从应用流程的角度来看,这样做存在问题。

主要是共享首选项中的值包括登录的用户会话令牌和用户名。

应用程序首先显示带有循环进度条的加载屏幕。然后,该应用程序读取共享首选项并在线连接以检查会话是否有效。如果没有会话,或者会话无效,则应用程序导航到询问用户名的登录“向导”,然后在下一页输入密码,然后在下一页进行 2 因素登录。之后,它导航到登录页面。如果加载页面找到有效会话,则跳过登录向导。

问题是应用程序状态和应用程序流程这两个东西是完全不同的。应用程序流可能会导致更改存储在应用程序状态中,但应用程序状态不应影响应用程序流,至少在概念上不会以这种方式。

实际上,即使上下文可用,我也不认为从 FutureProvider 的构建函数调用 Navigator.push() 是有效的。我可能是错的,但我觉得流动的方法更 Flutteronic。

 @override
 void initState() {
   super.initState();
   _loadSharedPrefs().then((_) {
     if(this.session.isValid()) _navToLandingPage();
     else _navToLoginStepOne();
     }
   }

我愿意接受更好的建议/指导

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 2016-04-25
    • 2020-12-07
    • 1970-01-01
    • 2020-11-11
    • 2020-11-08
    相关资源
    最近更新 更多