在InitState方法中是否有一种方法可以加载异步数据?

196

我希望在InitState方法中加载异步数据,我需要在build方法运行之前获取一些数据。我正在使用GoogleAuth代码,并且需要一直执行build方法,直到Stream运行。

我的initState方法是:

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

我将感激任何反馈。


4
StreamBuilder 是正确的解决方案。 - Rémi Rousselet
这段代码完全没有问题,不需要修改吗? - Jonah Williams
2
由于 initState() 只会被调用一次,那么在其中使用 setState() 有意义吗? - pragmateek
还要考虑使用FutyureBuilder,因为它在等待异步方法时只会阻塞一次;而流构建器模式是一系列不间断的未请求事件。 - Mark Parris
17个回答

3

样例代码:

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

    asyncOperation().then((val) {
      setState(() {});
      print("success");
    }).catchError((error, stackTrace) {
      print("outer: $error");
    });

//or

    asyncOperation().whenComplete(() {
      setState(() {});
      print("success");
    }).catchError((error, stackTrace) {
      print("outer: $error");
    });
  }

  Future<void> asyncOperation() async {
    await ... ;
  }

2

由于加载或等待初始状态通常只是一次性事件,因此FutureBuilder似乎是一个不错的选择,因为它会在异步方法上阻塞一次;异步方法可以是加载json配置、登录等。这里有一篇关于它的文章[链接]。(Flutter StreamBuilder vs FutureBuilder


1
@override
  void initState() {
    super.initState();
     _userStorage.getCurrentUser().then((user) {
      setState(() {
        if (user.isAuthenticated) {
          Timer.run(() {
            redirectTo();
          });
        }
      });
    });
  }

 void redirectTo() {
    Navigator.push(context,
        MaterialPageRoute(builder: (BuildContext context) => new ShopOrders()));
  }

0
我强烈建议使用FutureBuilder。它会执行异步函数并根据结果构建小部件!这里是一个简短介绍视频和文档的链接。 代码示例:
  Future<void> initControllers() async {
    for (var filePath in widget.videoFilePaths) {
      var val = VideoPlayerController.file(File(filePath));
      await val.initialize();
      controllers.add(val);
    }
  }


  @override
  Widget build(BuildContext context) {
    FutureBuilder(
          future: initControllers(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              return YourWidget();
            } else {
              return const ProgressIndicator();
            }
          },
        ));}

0

尝试了所有建议,但在我需要在initState()中完成的异步方法之后,没有一个可以阻止我的构建启动,除了一个:在State类中有一个布尔变量(让我们称其为_isDataLoaded),在定义时初始化为false,在initState()内部调用的setState()中设置为true,当异步函数完成时。在build中,根据此变量的值条件化使用CircleProcessIndicator()或您的Widget。

我知道这很糟糕,因为它可能会破坏构建,但老实说,对我来说没有其他更有意义的东西 - 例如在异步函数完成后运行super.initState() - 能够起作用。


-1

我来这里是因为我需要在程序启动时从FTP获取一些文件。我的项目是一个Flutter桌面应用程序。主线程下载FTP服务器上添加的最后一个文件,解密它并显示加密内容,此方法从initState()调用。我希望在GUI显示后在后台下载所有其他文件。

上述提到的方法都没有起作用。构建隔离相对复杂。

简单的方法是使用“compute”方法:

  1. 将从类中下载所有文件的方法移出。
  2. 将其设置为int函数,并带有int参数(我不使用int参数或结果)
  3. 从initState()方法调用它

这样,GUI就会显示,程序会在后台下载文件。

  void initState() {
    super.initState();
    _retrieveFileList(); // this gets the first file and displays it
    compute(_backgroundDownloader, 0); // this gets all the other files so that they are available in the local directory
  }

int _backgroundDownloader(int value) {
  var i = 0;
  new Directory('data').createSync();
  FTPClient ftpClient = FTPClient('www.guckguck.de',
      user: 'maxmusterman', pass: 'maxmusterpasswort');
  try {
    ftpClient.connect();
    var directoryContent = ftpClient.listDirectoryContent();
    // .. here, fileNames list is reconstructed from the directoryContent

    for (i = 0; i < fileNames.length; i++) {
      var dirName = "";
      if (Platform.isLinux)
        dirName = 'data/';
      else
        dirName = r'data\';
      var filePath = dirName + fileNames[i];
      var myDataFile = new File(filePath);
      if (!myDataFile.existsSync())
        ftpClient.downloadFile(fileNames[i], File(filePath));
    }
  } catch (err) {
    throw (err);
  } finally {
    ftpClient.disconnect();
  }
  return i;

-2

我在initState中使用了计时器

Timer timer;

@override
void initState() {
  super.initState();
  timer = new Timer.periodic(new Duration(seconds: 1), (Timer timer) async {
      await this.getUserVerificationInfo();
  });
}

@override
void dispose() {
    super.dispose();
    timer.cancel();
}

getUserVerificationInfo() async {
   await someAsyncFunc();
   timer.cancle();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接