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

2admgd59  于 2023-04-07  发布在  Flutter
关注(0)|答案(1)|浏览(125)

我想用Flutter构建一个数学应用程序。它应该具有基本功能。然而,我面临以下问题:当我的计时器超时并且我被引导到下一页时,出现以下错误消息:
在完成小部件树时抛出了以下Assert:查找已停用小部件的祖先是不安全的。
此时,小部件的元素树的状态不再稳定。
要在小部件的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);
          }
        }
      },
    );
  }

有人能帮我吗?

v8wbuo2f

v8wbuo2f1#

这是因为你在dispose of中调用了继承的widget,在你的示例中,这是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();
  }
}

相关问题