我正在寻找一种在InitState方法上加载异步数据的方法,在build方法运行之前,我需要一些数据。我正在使用GoogleAuth代码,并且需要执行构建方法,直到Stream运行为止。
我的initState方法是:
@override
void initState () {
super.initState();
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) {
setState(() {
_currentUser = account;
});
});
_googleSignIn.signInSilently();
}
感谢您的反馈。
答案 0 :(得分:6)
您可以使用 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(),
);
}
});
}
在上面的代码中, StreamBuilder 侦听内容的任何变化,最初是一个空数组,并显示 CircularProgressIndicator 。调用API后,将获取的数据添加到内容数组,该数组将运行 builder 方法。
当用户向下滚动时,将提取更多内容并将其添加到内容数组,该数组将再次运行 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
}
});
答案 1 :(得分:5)
您可以创建一个async
方法,并在您的initState
内调用
@override
void initState () {
super.initState();
_asyncMethod();
}
_asyncMethod() async {
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) {
setState(() {
_currentUser = account;
});
});
_googleSignIn.signInSilently();
}
答案 2 :(得分:3)
截至目前,使用.then
表示法似乎有效:
// ...
@override
initState() {
super.initState();
asyncFunction.then((result) {
print("result: $result");
setState(() {});
});
}
//...
答案 3 :(得分:3)
@override
void initState() {
super.initState();
asyncInitState(); // async is not allowed on initState() directly
}
void asyncInitState() async {
await yourAsyncCalls();
}
答案 4 :(得分:1)
您可以设置一个类似load的布尔值,并在您的监听函数中将其设置为true,并让build函数在load设置为true时返回您的数据,否则只需抛出CircularProgressIndicator
答案 5 :(得分:1)
由于加载或等待初始状态是一个(通常)独立事件 FutureBuilder 似乎是一个不错的选择,因为它在异步方法上阻塞一次;其中异步方法可能是加载 json 配置、登录等。在堆栈中 [here] 上有一个帖子。(Flutter StreamBuilder vs FutureBuilder)
答案 6 :(得分:1)
每个文档位于 https://pub.dev/packages/provider
initState() {
super.initState();
Future.microtask(() =>
context.read<MyNotifier>(context).fetchSomething(someValue);
);
}
答案 7 :(得分:0)
示例代码:
@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 ... ;
}
答案 8 :(得分:0)
甜蜜和简短:
(() async {
await your_method();
setState(() {....anything here});
})();
答案 9 :(得分:0)
@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()));
}
答案 10 :(得分:0)
initState() 和 build 不能是异步的,但在这些中,您可以调用异步函数而无需等待该函数
答案 11 :(得分:-1)
我来到这里是因为我需要在程序启动时从FTP提取一些文件。我的项目是一个颤抖的桌面应用程序。主线程下载最后添加到FTP服务器的文件,解密并显示加密的内容,此方法从initState()中调用。我想在GUI出现后在后台下载所有其他文件。
上述方法均无效。构建隔离区比较复杂。
最简单的方法是使用“计算”方法:
通过这种方式,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;
答案 12 :(得分:-1)
在visdat
中创建匿名函数,如下所示:
expandIcon