有没有办法在InitState方法上加载异步数据?

Jos*_*aza 19 dart flutter

我正在寻找一种在InitState方法上加载异步数据的方法,在构建方法运行之前我需要一些数据.我正在使用GoogleAuth代码,我需要执行构建方法,直到Stream运行.

我的initState方法是:

 @override
  void initState () {
    super.initState();
    _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account)     {
      setState(() {
        _currentUser = account;
      });
    });
    _googleSignIn.signInSilently();
  }
Run Code Online (Sandbox Code Playgroud)

我将不胜感激任何反馈.

die*_*per 19

您可以创建一个async方法并在您的内部调用它initState

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

    _asyncMethod() async {
     _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account)     {
        setState(() {
          _currentUser = account;
        });
      });
      _googleSignIn.signInSilently();
    }
Run Code Online (Sandbox Code Playgroud)

  • 在本例中,“build”在“_asyncMethod”完成之前执行! (5认同)
  • 除非他的通话是同步且即时的,否则不应更改任何内容。但是那没有异步问题 (4认同)
  • @diegoveloper 使用 `WidgetsBinding.instance.addPostFrameCallback` 而不是 @Nae 答案的目的是什么? (3认同)
  • 初始化状态时调用 setState() 是错误的,这会导致页面加载后刷新页面,因为您在 initState 中调用异步方法。解决方案只有FutureBuilder()。 (2认同)
  • @BISTech 使用 `WidgetsBinding.instance.addPostFrameCallback` 的原因是因为异步方法在没有回调的情况下调用 `setState()` ,可能会在 `initState()` 方法完成之前尝试更改状态,这是禁止的。 (2认同)

Nae*_*Nae 15

截至目前,使用.then符号似乎有效:

  // ...
  @override
  initState() {
    super.initState();
    asyncFunction.then((result) {
    print("result: $result");
    setState(() {});
    });
  }
  //...
Run Code Online (Sandbox Code Playgroud)

  • 如果您的异步函数没有返回任何内容,请改用“whenComplete”。 (22认同)
  • @Aravin 就我个人而言,我尽可能喜欢流。但这对于演示目的是“有效的”。我非常怀疑这是否是正确的方式。 (2认同)
  • @Eradicatore 听起来这个小部件在异步函数完成之前就被处理掉了。 (2认同)

iDe*_*ode 10

initState像这样在里面创建匿名函数:

@override
void initState() {
  super.initState();
  
  // Create anonymous function:
  () async {
    await _performYourTask();
    setState(() {
     // Update your UI with the desired changes. 
    });
  } ();
}
Run Code Online (Sandbox Code Playgroud)

  • 请有勇气说出反对票背后的原因。 (6认同)
  • 这与直接调用 `_performYourTask();` 有什么不同?用另一个未等待的异步函数包装异步函数有何帮助? (2认同)

Sup*_*iya 9

您可以创建一个异步方法并在initState中调用它

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

    asyncMethod(); ///initiate your method here
  }

Future<void> asyncMethod async{
 
 await ///write your method body here
}
Run Code Online (Sandbox Code Playgroud)


Tha*_*thu 8

您可以使用StreamBuilder执行此操作.只要流中的数据发生更改,这将运行构建器方法.

以下是我的一个示例项目的代码片段:

StreamBuilder<List<Content>> _getContentsList(BuildContext context) {
    final BlocProvider blocProvider = BlocProvider.of(context);
    int page = 1;
    return StreamBuilder<List<Content>>(
        stream: blocProvider.contentBloc.contents,
        initialData: [],
        builder: (context, snapshot) {
          if (snapshot.data.isNotEmpty) {
            return ListView.builder(itemBuilder: (context, index) {
              if (index < snapshot.data.length) {
                return ContentBox(content: snapshot.data.elementAt(index));
              } else if (index / 5 == page) {
                page++;
                blocProvider.contentBloc.index.add(index);
              }
            });
          } else {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
        });
  }
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,StreamBuilder监听内容的任何变化,最初是一个空数组并显示CircularProgressIndicator.一旦我进行API调用,就会将fetched数据添加到contents数组中,该数组将运行builder方法.

当用户向下滚动时,将获取更多内容并将其添加到内容数组中,这将再次运行构建器方法.

在您的情况下,只需要初始加载.但是,这为您提供了一个选项,可以在屏幕上显示其他内容,直到获取数据.

希望这是有帮助的.

编辑:

在你的情况下,我猜它将看起来如下所示:

StreamBuilder<List<Content>>(
        stream: account, // stream data to listen for change
        builder: (context, snapshot) {
            if(account != null) {
                return _googleSignIn.signInSilently();
            } else {
                // show loader or animation
            }
        });
Run Code Online (Sandbox Code Playgroud)

  • 对于方法2,有没有办法在await 调用结束时触发setState()?我尝试这样做,发现“mounted”现在为 false,因此 setState() 会产生错误。@雷米卢瑟莱特 (2认同)

Far*_*han 8

上一个答案!!

您可以设置一个布尔值,例如加载并在您的监听函数中将其设置为 true,并使您的构建函数在加载设置为 true 时返回您的数据,否则只抛出一个 CircularProgressIndicator

编辑 - 我不建议在您在 initState 中调用的方法中调用 setState。如果在调用 setState 时(在异步操作完成时)未安装小部件,则会报告错误。我建议你使用一个包after_layout

看看这个答案以更好地理解 initState 中的 setState :https ://stackoverflow.com/a/53373017/9206337

这篇文章将让您知道应用程序何时完成构建方法。这样您就可以在挂载小部件后等待异步方法设置状态:https : //stackoverflow.com/a/51273797/9206337


小智 6

  @override
  void initState() {
    super.initState();
    asyncInitState(); // async is not allowed on initState() directly
  }

  void asyncInitState() async {
    await yourAsyncCalls();
  }
Run Code Online (Sandbox Code Playgroud)

  • 不,不起作用。将打印放入 initState 并构建,asyncInitState 中的代码在构建后执行 (3认同)

小智 6

根据https://pub.dev/packages/provider上的文档

initState() {
  super.initState();
  Future.microtask(() =>
    context.read<MyNotifier>(context).fetchSomething(someValue);
  );
}
Run Code Online (Sandbox Code Playgroud)


Muh*_*qib 5

initState()并且build不能是异步的;但在这些中,您可以调用异步函数而无需等待该函数。


小智 5

这个怎么样?

@override
void initState() {
 //you are not allowed to add async modifier to initState
 Future.delayed(Duration.zero,() async {
  //your async 'await' codes goes here
 });
 super.initState();
}
Run Code Online (Sandbox Code Playgroud)