flutter await 不在 initState 等待
flutter await does not wait in initState
我是 flutter 的新手,所以我不确定我的编码方式是否正确。
我正在尝试从 firebase 获取数据,并想将其加载到 initState() 中。
但是,它等不及了。当进程处于等待状态时,它开始构建。
如何在构建之前加载数据。
谢谢
这些是代码和日志。
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/entity/quiz.dart';
import '../result.dart';
class Question extends StatefulWidget {
@override
_QuestionState createState() => _QuestionState();
}
class _QuestionState extends State<Question> {
@override
void initState() {
print("init State");
super.initState();
Future(() async {
await Future.delayed(Duration(seconds: 5));
});
setQuiz();
}
List<Quiz> quiz = [];
Future<void> setQuiz() async {
// 検索結果は、一旦はFuture型で取得
Future<QuerySnapshot<Map<String, dynamic>>> snapshot =
FirebaseFirestore.instance.collection("quiz").get();
print("inSetQuiz");
// ドキュメントを取得
quiz = await snapshot.then(
(event) => event.docs.map((doc) => Quiz.fromDocument(doc)).toList());
// await snapshot.then((value) {
// setState(() {
// quiz = value.docs.map((doc) => Quiz.fromDocument(doc)).toList();
// });
// });
print("afterSetQuiz");
print("hoge" + quiz.length.toString());
print("hoge" + quiz.elementAt(0).sentence);
}
// 問題番号
int questionNumber = 0;
// 正解問題数
int numOfCorrectAnswers = 0;
@override
Widget build(BuildContext context) {
print("in build");
return Scaffold(
appBar: AppBar(
title: Text("問題ページ"),
),
body: Center(
child:
Column(mainAxisAlignment: MainAxisAlignment.start, children: [
Container(
height: 50,
color: Colors.red,
child: const Center(
child: Text(
"一旦",
style: TextStyle(fontSize: 20),
),
),
),
Container(
padding: const EdgeInsets.all(8.0),
child: Text(
quiz.elementAt(questionNumber).sentence, ←error happens
style: TextStyle(fontSize: 20),
)),
omit
这里是日志↓
flutter: init State
flutter: inSetQuiz
flutter: in build
它在 await 函数之前加载构建。
您不应该推迟 initState 方法。这条直接来自 Flutter 错误的消息说明了一切:“initState 方法必须是没有 async 关键字的 void 方法;而不是直接在 initState 内部等待异步工作,只需调用一个单独的方法来完成这项工作,而无需等待它。
这就是 FutureBuilder 的用途。我将以这种方式重构应用程序:
- 保持你的 setQuiz 方法异步,但 return 不是 void Future,但是 Future 将数据包装成此方法 returns(在您的情况下,是测验)。
Future<List<Quiz>> setQuiz() {
// your existing code, just at the end do:
return quiz;
}
- 将 setQuiz 异步方法的 return 馈送到 FutureBuilder 小部件中:
@override
Widget build(BuildContext context) {
print("in build");
return Scaffold(
appBar: AppBar(
title: Text("問題ページ"),
),
body: FutureBuilder(
future: setQuiz(),
builder: (context, snapshot) {
if (snapshot.hasData) {
// out of the FutureBuilder's snapshot, collect the data
var quiz = snapshot.data as List<Quiz>;
// build your quiz structure here
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 50,
color: Colors.red,
child: const Center(
child: Text("一旦",
style: TextStyle(fontSize: 20),
),
),
),
ListView.builder(
itemCount: quiz.length,
itemBuilder: (context, index) {
var singleQuestion = quiz[index];
return Text(singleQuestion.sentence);
}
)
]
)
);
}
// while waiting for data to arrive, show a spinning indicator
return CircularProgressIndicator();
}
)
);
}
我是 flutter 的新手,所以我不确定我的编码方式是否正确。
我正在尝试从 firebase 获取数据,并想将其加载到 initState() 中。 但是,它等不及了。当进程处于等待状态时,它开始构建。 如何在构建之前加载数据。 谢谢
这些是代码和日志。
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/entity/quiz.dart';
import '../result.dart';
class Question extends StatefulWidget {
@override
_QuestionState createState() => _QuestionState();
}
class _QuestionState extends State<Question> {
@override
void initState() {
print("init State");
super.initState();
Future(() async {
await Future.delayed(Duration(seconds: 5));
});
setQuiz();
}
List<Quiz> quiz = [];
Future<void> setQuiz() async {
// 検索結果は、一旦はFuture型で取得
Future<QuerySnapshot<Map<String, dynamic>>> snapshot =
FirebaseFirestore.instance.collection("quiz").get();
print("inSetQuiz");
// ドキュメントを取得
quiz = await snapshot.then(
(event) => event.docs.map((doc) => Quiz.fromDocument(doc)).toList());
// await snapshot.then((value) {
// setState(() {
// quiz = value.docs.map((doc) => Quiz.fromDocument(doc)).toList();
// });
// });
print("afterSetQuiz");
print("hoge" + quiz.length.toString());
print("hoge" + quiz.elementAt(0).sentence);
}
// 問題番号
int questionNumber = 0;
// 正解問題数
int numOfCorrectAnswers = 0;
@override
Widget build(BuildContext context) {
print("in build");
return Scaffold(
appBar: AppBar(
title: Text("問題ページ"),
),
body: Center(
child:
Column(mainAxisAlignment: MainAxisAlignment.start, children: [
Container(
height: 50,
color: Colors.red,
child: const Center(
child: Text(
"一旦",
style: TextStyle(fontSize: 20),
),
),
),
Container(
padding: const EdgeInsets.all(8.0),
child: Text(
quiz.elementAt(questionNumber).sentence, ←error happens
style: TextStyle(fontSize: 20),
)),
omit
这里是日志↓
flutter: init State
flutter: inSetQuiz
flutter: in build
它在 await 函数之前加载构建。
您不应该推迟 initState 方法。这条直接来自 Flutter 错误的消息说明了一切:“initState 方法必须是没有 async 关键字的 void 方法;而不是直接在 initState 内部等待异步工作,只需调用一个单独的方法来完成这项工作,而无需等待它。
这就是 FutureBuilder 的用途。我将以这种方式重构应用程序:
- 保持你的 setQuiz 方法异步,但 return 不是 void Future,但是 Future 将数据包装成此方法 returns(在您的情况下,是测验)。
Future<List<Quiz>> setQuiz() {
// your existing code, just at the end do:
return quiz;
}
- 将 setQuiz 异步方法的 return 馈送到 FutureBuilder 小部件中:
@override
Widget build(BuildContext context) {
print("in build");
return Scaffold(
appBar: AppBar(
title: Text("問題ページ"),
),
body: FutureBuilder(
future: setQuiz(),
builder: (context, snapshot) {
if (snapshot.hasData) {
// out of the FutureBuilder's snapshot, collect the data
var quiz = snapshot.data as List<Quiz>;
// build your quiz structure here
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 50,
color: Colors.red,
child: const Center(
child: Text("一旦",
style: TextStyle(fontSize: 20),
),
),
),
ListView.builder(
itemCount: quiz.length,
itemBuilder: (context, index) {
var singleQuestion = quiz[index];
return Text(singleQuestion.sentence);
}
)
]
)
);
}
// while waiting for data to arrive, show a spinning indicator
return CircularProgressIndicator();
}
)
);
}