Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dart 有没有办法在InitState方法上加载异步数据?_Dart_Flutter - Fatal编程技术网

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

Dart 有没有办法在InitState方法上加载异步数据?,dart,flutter,Dart,Flutter,我正在寻找一种在InitState方法上加载异步数据的方法,在构建方法运行之前,我需要一些数据。我使用的是GoogleAuth代码,我需要执行build方法,直到流运行为止 我的initState方法是: @override void initState () { super.initState(); _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) { set

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

我的initState方法是:

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

我将非常感谢您的反馈。

方法1:您可以使用StreamBuilder来完成此操作。每当流中的数据发生更改时,将运行builder方法

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

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(),
            );
          }
        });
  }

您可以创建一个
async
方法,并在
initState

@覆盖
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((){
_异步方法();
});
}
_asyncMethod()异步{
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount帐户){
设置状态(){
_当前用户=帐户;
});
});
_googleSignIn.signizely();
}

现在使用的是
。然后
符号似乎起作用:

  // ...
  @override
  initState() {
    super.initState();
    myAsyncFunction
    // as suggested in the comment
    // .whenComplete() {
    // or
      .then((result) {
    print("result: $result");
    setState(() {});
    });
  }
  //...
先前的答案

您可以在listen函数中设置一个类似loaded的布尔值,并将其设置为true,当loaded设置为true时,让构建函数返回数据,否则只需抛出一个CircularProgressIndicator

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

为了更好地理解initState中的setState,请查看此答案:

这篇文章将让你了解应用程序何时完成构建方法。因此,您可以在挂载小部件后等待异步方法设置状态:

示例代码:

 @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 ... ;
  }
@覆盖
void initState(){
super.initState();
asyncOperation()。然后((val){
setState((){});
打印(“成功”);
}).catchError((错误,堆栈跟踪){
打印(“外部:$error”);
});
//或
asyncOperation()。当完成(){
setState((){});
打印(“成功”);
}).catchError((错误,堆栈跟踪){
打印(“外部:$error”);
});
}
Future asyncOperation()异步{
等待;
}
甜美而简短:

(()异步{
等待你的_方法();
setState((){……这里的任何内容});
})();

@覆盖
void initState(){
super.initState();
_userStorage.getCurrentUser().then((用户){
设置状态(){
if(user.isAuthenticated){
Timer.run(){
重定向到();
});
}
});
});
}
无效重定向到(){
Navigator.push(上下文,
MaterialPackageRoute(生成器:(BuildContext上下文)=>new ShopOrders());
}

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

上述方法都不起作用。构建一个隔离是相对复杂的

简单的方法是使用“计算”方法:

  • 将从FTP下载所有文件的方法移出类
  • 将其设置为带有int参数的int函数(我不使用int参数或结果)
  • 从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;
    
    void initState(){
    super.initState();
    _retrieveFileList();//这将获取并显示第一个文件
    compute(_backgroundDownloader,0);//这将获取所有其他文件,以便它们在本地目录中可用
    }
    int_backgroundDownloader(int值){
    var i=0;
    新目录('data')。createSync();
    FTPClient FTPClient=FTPClient('www.guckguck.de',
    用户:“maxmusterman”,密码:“maxmusterpasswort”);
    试一试{
    ftpClient.connect();
    var directoryContent=ftpClient.listDirectoryContent();
    //…这里,文件名列表是从directoryContent重建的
    对于(i=0;i
    initState
    中创建匿名函数,如下所示:

    @覆盖
    void initState(){
    super.initState();
    //创建匿名函数:
    ()异步{
    等待执行任务();
    设置状态(){
    //使用所需的更改更新UI。
    });
    } ();
    }
    
    initState()build不能是异步的,但是在这些函数中,您可以调用异步的函数,而无需等待该函数

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

    @override
      void initState() {
        super.initState();
    
        Future.delayed(Duration.zero, () async {
          
         //type your method here
    
        });
      }
    

    除非他的调用是同步的和即时的,否则不应该更改任何内容。但是这样就没有异步问题了。在这种情况下,在
    \u asyncMethod
    完成之前执行
    build
    。@diegoveloper使用
    WidgetsBinding.instance.addPostFrameCallback
    而不是@Nae answer?调用setState()是错误的当您初始化状态时,这会导致在加载页面后刷新页面,因为您正在initState中调用异步方法。解决方案只有FutureBuilder()。不,没关系,因为我使用的是WidgetsBinding.instance.addPostFrameCallback @override void initState() { super.initState(); asyncInitState(); // async is not allowed on initState() directly } void asyncInitState() async { await yourAsyncCalls(); }
      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;
    
    @override
      void initState() {
        super.initState();
    
        Future.delayed(Duration.zero, () async {
          
         //type your method here
    
        });
      }