在其 dispose() 方法中安全地引用小部件的祖先



我想用Flutter建立一个数学应用程序。它应该有基本的功能。然而,我面临着以下问题:当我的计时器用完,我被定向到下一页时,出现以下错误消息:

在完成小部件树时抛出了以下断言:查找一个已停用的小部件的祖先是不安全的。

此时,小部件的元素树的状态不再稳定。

要安全地在其dispose()方法中引用小部件的祖先,请在小部件的didChangeDependencies()方法中调用dependOnInheritedWidgetOfExactType()来保存对祖先的引用。

class MathFunctionScreen extends StatefulWidget {
static String id = "MathFunctionScreen";
const MathFunctionScreen({Key? key}) : super(key: key);
@override
State<MathFunctionScreen> createState() => _MathFunctionScreenState();
}
class _MathFunctionScreenState extends State<MathFunctionScreen>
with TickerProviderStateMixin {
DataBase db = DataBase();
late int myTime;
late int timeStamp;
@override
void initState() {
print("initState() wurde ausgeführt");
Provider.of<NumberGenerator>(context, listen: false).ctrl;
myOnChange();
Provider.of<NumberGenerator>(context, listen: false).mathCorrectAnswer;
Provider.of<NumberGenerator>(context, listen: false).operator;
Provider.of<NumberGenerator>(context, listen: false).setDatabase();
Provider.of<TimerProvider>(context, listen: false).startTimer(context);
animationController;
offsetAnimation;
animationController.forward();
super.initState();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
@override
void dispose() {
Provider.of<TimerProvider>(context, listen: false).timer.cancel();
Provider.of<NumberGenerator>(context, listen: false)
.ctrl
.removeListener(() {});
animationController.dispose();
super.dispose();
}
late AnimationController animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 600),
);
late Animation<Offset> offsetAnimation =
Tween<Offset>(begin: const Offset(-3, 0), end: Offset.zero).animate(
CurvedAnimation(parent: animationController, curve: Curves.easeIn),
);
void myOnChange() {
Provider.of<NumberGenerator>(context, listen: false)
.textFieldTextChange(animationController);
}
void _updateText(String text) async {
String answer = (await Provider.of<NumberGenerator>(context, listen: false)
.mathCorrectAnswer)
.toString();
int answerLength = answer.length;
setState(() {
if (Provider.of<NumberGenerator>(context, listen: false)
.ctrl
.text
.length <
answerLength) {
Provider.of<NumberGenerator>(context, listen: false).ctrl.text =
Provider.of<NumberGenerator>(context, listen: false).ctrl.text +
text;
}
});
}
@override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;

下面的方法在一个叫做NumberGenerator的类中,它继承了ChangeNotifier

void textFieldTextChange(AnimationController animationController) {
ctrl.addListener(
() async {
String mathCorrectAnswerString = (await mathCorrectAnswer).toString();
// user hat die zulässige Länge erreicht
if (ctrl.text.length >= mathCorrectAnswerString.length) {
//this delayed ist, damit die letzte zahl noch gesehen werden kann!
await Future.delayed(const Duration(milliseconds: 200));
checkAnswer(ctrl.text == mathCorrectAnswerString);
if (ctrl.text == mathCorrectAnswerString) {
updateDatabaseResult();
await Future.delayed(const Duration(milliseconds: 20));
wrongAnswers.clear();
wrongAnswers.add(addRightIcon);
notifyListeners();
await Future.delayed(const Duration(milliseconds: 500));
wrongAnswers.clear();
updateLeftAndRightInt();
setDatabase();
animationController.reset();
animationController.forward();
notifyListeners();
} else if (ctrl.text != mathCorrectAnswerString &&
(wrongAnswers.length <= 1)) {
updateDatabaseResult();
wrongAnswers.add(addWrongIcon);
notifyListeners();
await Future.delayed(const Duration(milliseconds: 500));
ctrl.clear();
} else {
updateDatabaseResult();
wrongAnswers.add(addWrongIcon);
notifyListeners();
await Future.delayed(const Duration(seconds: 1));
updateLeftAndRightInt();
setDatabase();
animationController.reset();
animationController.forward();
wrongAnswers.clear();
notifyListeners();
}
}

下面的类包含计时器。当它过期时,我被重定向到新页面并收到错误消息:

class TimerProvider extends ChangeNotifier {
late Timer timer;
late int value;
String collectionTime = "Time";
String key = "myTime";
startTimer(BuildContext context) {
timer = Timer.periodic(
const Duration(seconds: 1),
(timer) async {
if (value > 0) {
value--;
notifyListeners();
} else if (value <= 0) {
final QuerySnapshot<Map<String, dynamic>> documents =
await FirebaseFirestore.instance
.collection('Funktionen')
.where('result', isEqualTo: "")
.get();
final List<Future<void>> deleteFutures = [];
for (final QueryDocumentSnapshot<Map<String, dynamic>> document
in documents.docs) {
deleteFutures.add(document.reference.delete());
}
await Future.wait(deleteFutures);
timer.cancel();
if (context.mounted) {
Navigator.pushReplacementNamed(context, UserResultScreen.id);
// Navigator.pushNamed(context, UserResultScreen.id);
}
}
},
);
}

有人能帮我一下吗?

这是因为您在示例中调用了dispose中的继承小部件这是provider。of<"Type">

你需要这样做:

class _MathFunctionScreenState extends State<MathFunctionScreen>
with TickerProviderStateMixin {
...
NumberGenerator numberGenerator;
TimerProvider timerProvider;
...
@override
void didChangeDependencies() {
numberGenerator = Provider.of<NumberGenerator>;
timerProvider = Provider.of<TimerProvider>;
super.didChangeDependencies();
}
@override
void dispose() {
timerProvider.timer.cancel();
numberGenerator.ctrl.removeListener(() {});
animationController.dispose();
super.dispose();
}
}

相关内容

  • 没有找到相关文章

最新更新