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

ayc*_*cha 6 navigation flutter flutter-dependencies flutter-state

我想用 Flutter 构建一个数学应用程序。应该有基本的功能。但是,我面临以下问题:当我的计时器耗尽并且我被定向到下一页时,会出现以下错误消息:

\n

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

\n

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

\n

要在 widget 的 dispose() 方法中安全地引用它的祖先,请通过在 widget 的 didChangeDependency() 方法中调用 dependentOnInheritedWidgetOfExactType() 来保存对祖先的引用。

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

而下面的方法是在一个名为NumberGenerator的类中,该类继承了ChangeNotifier

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

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

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

有人可以帮我弄这个吗 ?

\n

小智 8

这是因为您在 dispose of 中调用了继承的小部件,在您的示例中这是 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();
  }
}
Run Code Online (Sandbox Code Playgroud)