Search code examples
flutterfunctional-programmingcontrollerstatedispose

Dispose isn't called when the widgets removed from the window - Flutter


I am using the same stateful widget in 2 different views. It's using a list of TextEditingController that I send as a delegate through

this is the list of TextControllers :

var textfieldControllersEx = [
  TextEditingController(),
  TextEditingController(),
  TextEditingController(),
  TextEditingController(),
];

the Extracted widget is used twice in 2 different views:

ExpiryDateTextField(
  controllers: textfieldControllersEx,
  onChangeF: (String value, int i) {
    setState(() {
        _addValuesToAr(value, i);
    });
  },
),

on every view I call a dispose and a dispose in the ExpiryDateTextField Function as well with a print to see if it's being disposed:

It doesn't even call the dispose on either pages

@override
  void dispose() {
    Print.yellow('DISPOSED');
    textfieldControllersEx[0].dispose();
    textfieldControllersEx[1].dispose();
    textfieldControllersEx[2].dispose();
    textfieldControllersEx[3].dispose();
    textfieldControllersEx[0].text = null;
    textfieldControllersEx[1].text = null;
    textfieldControllersEx[2].text = null;
    textfieldControllersEx[3].text = null;
    // TODO: implement dispose
    super.dispose();
  }

this is the function :

var focusNodes = [
  FocusNode(),
  FocusNode(),
  FocusNode(),
  FocusNode(),
];
class ExpiryDateTextField extends StatefulWidget {
  final List<TextEditingController> controllers;
  final Function onChangeF;
  ExpiryDateTextField({this.controllers, this.onChangeF});
  @override
  _ExpiryDateTextFieldState createState() => _ExpiryDateTextFieldState();
}
class _ExpiryDateTextFieldState extends State<ExpiryDateTextField> {
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    bool onSwitchChanged(value, context, index) {
      // print(index++);
      if (index == 4) {
        //if it is on the last text box, do nothing
      } else {
        if (widget.controllers[index].text.length > 0) {
          index++;
          FocusScope.of(context).requestFocus(focusNodes[index]);
          widget.controllers[index].selection = TextSelection(
            baseOffset: 0,
            extentOffset: widget.controllers[index].text.length
          );
          // FocusScope.of(context).focus
        }
      }
      return true;
    }
    return Row(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: SingleDigitTextField(
            onChangedF: (value) {
              widget.onChangeF(value, 0);
              print(this.toString(minLevel: DiagnosticLevel.debug));
              onSwitchChanged(value, context, 0);
            },
            fNode: focusNodes[0],
            cController: widget.controllers[0]
          ),
        ),
        Expanded(
          flex: 1,
          child: SingleDigitTextField(
            onChangedF: (value) {
              widget.onChangeF(value, 1);
              onSwitchChanged(value, context, 1);
            },
            fNode: focusNodes[1],
            cController: widget.controllers[1]
          ),
        ),
        Expanded(
          flex: 1,
          child: Text("/",
            textAlign: TextAlign.center,
            style: Theme.of(context).textTheme.display2
          ),
        ),
        Expanded(
          flex: 1,
          child: SingleDigitTextField(
            onChangedF: (value) {
              widget.onChangeF(value, 2);
              onSwitchChanged(value, context, 2);
            },
            fNode: focusNodes[2],
            cController: widget.controllers[2]
          ),
        ),
        Expanded(
          flex: 1,
          child: SingleDigitTextField(
            onChangedF: (value) {
              widget.onChangeF(value, 3);
              onSwitchChanged(value, context, 3);
            },
            fNode: focusNodes[3],
            cController: widget.controllers[3]
          ),
        ),
      ],
    );
  }
}

this is the error given :

I/flutter (24293): Another exception was thrown: dependOnInheritedWidgetOfExactType<_ModalScopeStatus>() or dependOnInheritedElement() was called before _ViewState.initState() completed.

I saw this example but it didn't work because if a value is changed it disposes of the TextControllers immediately :

@override
  void didChangeDependencies() {
    textfieldControllersEx[0].dispose();
    textfieldControllersEx[1].dispose();
    textfieldControllersEx[2].dispose();
    textfieldControllersEx[3].dispose();
    // TODO: implement didChangeDependencies
    super.didChangeDependencies();
  }

this is how I Navigate :

Navigator.of(context).pushNamed("/PlaidPage");

Help would be kindly appreciated


Solution

  • The reason why dispose() isn't called is because the Screen is still on the Navigation stack. You can remove the current screen by either using Navigator.pop() or Navigator.of(context).pushNamedAndRemoveUntil() - to remove till the specified page and navigate to the next page.